Skip to content

Commit

Permalink
feat(dashboard api): include verification tags
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Jan 23, 2018
1 parent d2a9e30 commit e8d0fae
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 16 deletions.
1 change: 1 addition & 0 deletions db/migrations/000050_create_latest_matrix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# latest verification for each provider version)
# Must include lines where verification_id is null so that we don't
# lose the unverified pacts.
# In this view there will be one row for each consumer version/provider version
create_view(:latest_matrix,
"SELECT matrix.* FROM matrix
INNER JOIN latest_verification_id_for_consumer_version_and_provider_version AS lv
Expand Down
43 changes: 43 additions & 0 deletions db/migrations/20180123_create_latest_verification_tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Sequel.migration do
change do
# the provider version order of the latest verification for each consumer/provider/tag
create_view(:latest_tagged_verification_provider_version_orders,
"
select m.consumer_id, m.provider_id, t.name as tag_name, max(m.provider_version_order) as latest_provider_version_order
from latest_matrix m
inner join tags t
on m.provider_version_id = t.version_id
where m.provider_version_order is not null
group by m.consumer_id, m.provider_id, t.name
"
)

=begin
The tags for which the given verification is the latest of that tag
Imagine that:
provider v1 has verification
has tag dev
has tag prod <- latest
provider v2 has verification
has tag dev <-latest
provider v3 has tag dev
This table would contain the prod tag row for the v1 verification
This table would contain the dev tag row for the v2 verification
=end
create_view(:latest_verification_tags,
"
select t.*, m.verification_id
from latest_matrix m
inner join latest_tagged_verification_provider_version_orders l
on m.consumer_id = l.consumer_id
and m.provider_id = l.provider_id
and m.provider_version_order = l.latest_provider_version_order
inner join tags t
on l.tag_name = t.name
and m.provider_version_id = t.version_id
"
)
end
end
16 changes: 16 additions & 0 deletions lib/pact_broker/api/decorators/dashboard_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def index_item_hash(consumer, provider, consumer_version, index_item, base_url)
pact: pact_hash(index_item, base_url),
pactTags: pact_tags(index_item, base_url),
latestVerificationResult: verification_hash(index_item, base_url),
latestVerificationResultTags: verification_tags(index_item, base_url),
verificationStatus: index_item.verification_status.to_s,
webhookStatus: index_item.webhook_status.to_s,
latestWebhookExecution: latest_webhook_execution(index_item, base_url),
Expand Down Expand Up @@ -125,6 +126,21 @@ def pact_tags(index_item, base_url)
end
end

def verification_tags(index_item, base_url)
index_item.latest_verification_latest_tags.collect do | tag |
fake_tag = OpenStruct.new(name: tag.name, version: index_item.provider_version)
{
name: tag.name,
latest: true,
_links: {
self: {
href: tag_url(base_url, fake_tag)
}
}
}
end
end

def latest_webhook_execution(index_item, base_url)
if index_item.last_webhook_execution_date
{
Expand Down
9 changes: 5 additions & 4 deletions lib/pact_broker/domain/index_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ module PactBroker
module Domain
class IndexItem

attr_reader :consumer, :provider, :latest_pact, :latest_verification, :webhooks, :triggered_webhooks
attr_reader :consumer, :provider, :latest_pact, :latest_verification, :webhooks, :triggered_webhooks, :latest_verification_latest_tags

def initialize consumer, provider, latest_pact = nil, latest = true, latest_verification = nil, webhooks = [], triggered_webhooks = [], tags = []
def initialize consumer, provider, latest_pact = nil, latest = true, latest_verification = nil, webhooks = [], triggered_webhooks = [], tags = [], latest_verification_latest_tags = []
@consumer = consumer
@provider = provider
@latest_pact = latest_pact
Expand All @@ -16,10 +16,11 @@ def initialize consumer, provider, latest_pact = nil, latest = true, latest_veri
@webhooks = webhooks
@triggered_webhooks = triggered_webhooks
@tags = tags
@latest_verification_latest_tags = latest_verification_latest_tags
end

def self.create consumer, provider, latest_pact, latest, latest_verification, webhooks = [], triggered_webhooks = [], tags = []
new consumer, provider, latest_pact, latest, latest_verification, webhooks, triggered_webhooks, tags
def self.create consumer, provider, latest_pact, latest, latest_verification, webhooks = [], triggered_webhooks = [], tags = [], latest_verification_latest_tags = []
new consumer, provider, latest_pact, latest, latest_verification, webhooks, triggered_webhooks, tags, latest_verification_latest_tags
end

def eq? other
Expand Down
17 changes: 13 additions & 4 deletions lib/pact_broker/index/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ def self.find_index_items options = {}
if options[:tags]
tagged_rows = PactBroker::Matrix::Row
.select_all_qualified
.select_append(:tag_name)
.join(:head_pact_publications, {id: :pact_publication_id})
.select_append(Sequel[:head_pact_publications][:tag_name])
.join(:head_pact_publications, {consumer_id: :consumer_id, provider_id: :provider_id, consumer_version_order: :consumer_version_order})
.eager(:latest_triggered_webhooks)
.eager(:webhooks)
.order(:consumer_name, :provider_name)
.eager(:consumer_version_tags)
.eager(:latest_verification_tags)

if options[:tags].is_a?(Array)
tagged_rows = tagged_rows.where(Sequel[:head_pact_publications][:tag_name] => options[:tags]).or(Sequel[:head_pact_publications][:tag_name] => nil)
Expand All @@ -43,7 +44,7 @@ def self.find_index_items options = {}
tagged_rows = tagged_rows.all
.group_by(&:pact_publication_id)
.values
.collect{|group| [group.first, group.collect{|r| r[:tag_name]}.compact] }
.collect{|group| [group.last, group.collect{|r| r[:tag_name]}.compact] }
.collect{ |(row, tag_names)| row.consumer_head_tag_names = tag_names; row }

rows = tagged_rows
Expand All @@ -59,7 +60,15 @@ def self.find_index_items options = {}
end
end
previous_index_item_for_same_consumer_and_provider = index_items.last && index_items.last.consumer_name == row.consumer_name && index_items.last.provider_name == row.provider_name
index_items << PactBroker::Domain::IndexItem.create(row.consumer, row.provider, row.pact, !previous_index_item_for_same_consumer_and_provider, row.latest_verification, row.webhooks, row.latest_triggered_webhooks, tag_names)
index_items << PactBroker::Domain::IndexItem.create(row.consumer, row.provider,
row.pact,
!previous_index_item_for_same_consumer_and_provider,
row.latest_verification,
row.webhooks,
row.latest_triggered_webhooks,
tag_names,
row.latest_verification_tags
)
end

index_items
Expand Down
2 changes: 2 additions & 0 deletions lib/pact_broker/matrix/row.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'pact_broker/repositories/helpers'
require 'pact_broker/webhooks/latest_triggered_webhook'
require 'pact_broker/tags/latest_verification_tag'

module PactBroker
module Matrix
Expand All @@ -13,6 +14,7 @@ class Row < Sequel::Model(:matrix)
# TODO modify this to work with single pacticipant webhooks
associate(:one_to_many, :webhooks, :class => "PactBroker::Webhooks::Webhook", primary_key: [:consumer_id, :provider_id], key: [:consumer_id, :provider_id])
associate(:one_to_many, :consumer_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :consumer_version_id, key: :version_id)
associate(:one_to_many, :latest_verification_tags, :class => "PactBroker::Tags::LatestVerificationTag", primary_key: :verification_id, key: :verification_id)

dataset_module do
include PactBroker::Repositories::Helpers
Expand Down
14 changes: 14 additions & 0 deletions lib/pact_broker/tags/latest_verification_tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'pact_broker/db'
require 'pact_broker/repositories/helpers'

module PactBroker
module Tags
# The tag associated with the latest verification for a given tag
class LatestVerificationTag < Sequel::Model

dataset_module do
include PactBroker::Repositories::Helpers
end
end
end
end
11 changes: 11 additions & 0 deletions spec/fixtures/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@
}
}
],
"latestVerificationResultTags": [
{
"name": "dev",
"latest": true,
"_links": {
"self": {
"href": "verification_dev_tag_url"
}
}
}
],
"pact": {
"_links": {
"self": {
Expand Down
18 changes: 13 additions & 5 deletions spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module Decorators
verification_status: 'wiffle',
provider_version_number: provider_version.number,
consumer_version_number: consumer_version.number,
tag_names: ['prod']
tag_names: ['prod'],
latest_verification_latest_tags: [double('tag', name: 'dev')]
)
end
let(:consumer) { instance_double('PactBroker::Domain::Pacticipant', name: 'Foo') }
Expand All @@ -42,10 +43,17 @@ module Decorators
allow_any_instance_of(DashboardDecorator).to receive(:version_url).with(base_url, consumer_version).and_return('consumer_version_url')
allow_any_instance_of(DashboardDecorator).to receive(:webhooks_status_url).with(consumer, provider, base_url).and_return('webhooks_status_url')
allow_any_instance_of(DashboardDecorator).to receive(:tag_url) do | instance, base_url, tag |
expect(tag.name).to eq 'prod'
expect(tag.version).to be consumer_version
expect(base_url).to eq base_url
'pact_prod_tag_url'
if tag.version == consumer_version
expect(tag.name).to eq 'prod'
expect(tag.version).to be consumer_version
expect(base_url).to eq base_url
'pact_prod_tag_url'
else
expect(tag.name).to eq 'dev'
expect(tag.version).to be provider_version
expect(base_url).to eq base_url
'verification_dev_tag_url'
end
end
end

Expand Down
17 changes: 17 additions & 0 deletions spec/lib/pact_broker/index/service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module Index
.create_consumer_version_tag("also-ignored")
.create_pact
.create_verification(provider_version: "2.1.0")
.use_provider_version("2.1.0")
end

let(:rows) { subject.find_index_items(options) }
Expand Down Expand Up @@ -93,6 +94,22 @@ module Index
expect(rows.first.latest_verification.provider_version_number).to eq '2.0.0'
end
end

context "when the verification is the latest for a given tag" do
before do
td.create_pact_with_hierarchy("Foo", "1", "Bar")
.create_verification(provider_version: "1.0.0", tag_names: ['dev', 'prod'])
.create_verification(provider_version: "2.0.0", number: 2, tag_names: ['dev'])
end

let(:rows) { subject.find_index_items(options) }
let(:options) { { tags: true } }

it "includes the names of the tags for which the verification is the latest of that tag" do
expect(rows.first.provider_version_number).to eq "2.0.0"
expect(rows.first.latest_verification_latest_tags.collect(&:name)).to eq ['dev']
end
end
end
end
end
Expand Down
85 changes: 85 additions & 0 deletions spec/migrations/20180123_create_latest_verification_tags_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
describe 'latest tagged verifications', migration: true do
before do
PactBroker::Database.migrate(20180123)
end

let(:now) { DateTime.new(2018, 2, 2) }
let!(:consumer) { create(:pacticipants, {name: 'C', created_at: now, updated_at: now}) }
let!(:provider) { create(:pacticipants, {name: 'P', created_at: now, updated_at: now}) }
let!(:consumer_version_1) { create(:versions, {number: '1', order: 1, pacticipant_id: consumer[:id], created_at: now, updated_at: now}) }
let!(:consumer_version_2) { create(:versions, {number: '2', order: 2, pacticipant_id: consumer[:id], created_at: now, updated_at: now}) }

let!(:provider_version_1) { create(:versions, {number: '1', order: 1, pacticipant_id: provider[:id], created_at: now, updated_at: now}) }
let!(:provider_version_2) { create(:versions, {number: '2', order: 2, pacticipant_id: provider[:id], created_at: now, updated_at: now}) }
let!(:provider_version_3) { create(:versions, {number: '3', order: 3, pacticipant_id: provider[:id], created_at: now, updated_at: now}) }

let!(:provider_version_1_prod_tag) { create(:tags, {version_id: provider_version_1[:id], name: 'prod', created_at: now, updated_at: now}, nil) }
let!(:provider_version_1_dev_tag) { create(:tags, {version_id: provider_version_1[:id], name: 'dev', created_at: now, updated_at: now}, nil) }
let!(:provider_version_2_dev_tag) { create(:tags, {version_id: provider_version_2[:id], name: 'dev', created_at: now, updated_at: now}, nil) }

let!(:pact_version_1) { create(:pact_versions, {content: {some: 'json'}.to_json, sha: '1', consumer_id: consumer[:id], provider_id: provider[:id], created_at: now}) }
let!(:pact_version_2) { create(:pact_versions, {content: {some: 'json other'}.to_json, sha: '2', consumer_id: consumer[:id], provider_id: provider[:id], created_at: now}) }
#let!(:pact_version_3) { create(:pact_versions, {content: {some: 'json more'}.to_json, sha: '3', consumer_id: consumer[:id], provider_id: provider[:id], created_at: now}) }
let!(:pact_publication_1) do
create(:pact_publications, {
consumer_version_id: consumer_version_1[:id],
provider_id: provider[:id],
revision_number: 1,
pact_version_id: pact_version_1[:id],
created_at: now
})
end

let!(:pact_publication_2) do
create(:pact_publications, {
consumer_version_id: consumer_version_2[:id],
provider_id: provider[:id],
revision_number: 1,
pact_version_id: pact_version_2[:id],
created_at: now
})
end

# provider v1
let!(:verification_1) do
create(:verifications, {
number: 1,
success: true,
provider_version_id: provider_version_1[:id],
pact_version_id: pact_version_1[:id],
execution_date: now,
created_at: now
})
end

# provider v2
let!(:verification_2) do
create(:verifications, {
number: 2,
success: true,
provider_version_id: provider_version_2[:id],
pact_version_id: pact_version_1[:id],
execution_date: now,
created_at: now
})
end

# provider v2
let!(:verification_3) do
create(:verifications, {
number: 3,
success: true,
provider_version_id: provider_version_2[:id],
pact_version_id: pact_version_1[:id],
execution_date: now,
created_at: now
})
end

it "includes the tag rows for which the related verification is the latest of that tag" do
rows = database[:latest_verification_tags].all
expect(rows).to contain_hash(verification_id: verification_1[:id], name: 'prod')
expect(rows).to contain_hash(verification_id: verification_3[:id], name: 'dev')
expect(rows.size).to eq 2
end
end
2 changes: 1 addition & 1 deletion spec/support/migration_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module MigrationHelpers
def create table_name, params, id_column_name = :id
database[table_name].insert(params);
database[table_name].order(id_column_name).last
database[table_name].order(id_column_name).last if id_column_name
end

def clean table_name
Expand Down
8 changes: 6 additions & 2 deletions spec/support/rspec_match_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@


def contains_hash?(expected, actual)
expected.all? do |key, value|
unordered_match(actual[key], value)
if actual.is_a?(Array)
actual.any? && actual.any?{|actual_item| contains_hash?(expected, actual_item)}
else
expected.all? do |key, value|
unordered_match(actual[key], value)
end
end
end

Expand Down
7 changes: 7 additions & 0 deletions spec/support/test_data_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,19 @@ def create_deprecated_webhook_execution params = {}
end

def create_verification parameters = {}
tag_names = [parameters.delete(:tag_names), parameters.delete(:tag_name)].flatten.compact
provider_version_number = parameters[:provider_version] || '4.5.6'
default_parameters = {success: true, number: 1, test_results: {some: 'results'}}
parameters = default_parameters.merge(parameters)
parameters.delete(:provider_version)
verification = PactBroker::Domain::Verification.new(parameters)
@verification = PactBroker::Verifications::Repository.new.create(verification, provider_version_number, @pact)
if tag_names.any?
provider_version = PactBroker::Domain::Version.where(pacticipant_id: @provider.id, number: provider_version_number).single_record
tag_names.each do | tag_name |
PactBroker::Domain::Tag.create(name: tag_name, version: provider_version)
end
end
self
end

Expand Down

0 comments on commit e8d0fae

Please sign in to comment.