pact_broker 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/lib/pact_broker/api/decorators/version_decorator.rb +1 -1
  4. data/lib/pact_broker/api/decorators/webhook_decorator.rb +3 -3
  5. data/lib/pact_broker/api/decorators/webhooks_decorator.rb +10 -2
  6. data/lib/pact_broker/api/resources/version.rb +6 -1
  7. data/lib/pact_broker/app.rb +6 -1
  8. data/lib/pact_broker/doc/views/webhooks-create.markdown +38 -0
  9. data/lib/pact_broker/doc/views/webhooks-webhooks.markdown +15 -0
  10. data/lib/pact_broker/domain/order_versions.rb +15 -1
  11. data/lib/pact_broker/pacticipants/service.rb +4 -2
  12. data/lib/pact_broker/pacts/repository.rb +4 -0
  13. data/lib/pact_broker/tags/repository.rb +4 -0
  14. data/lib/pact_broker/version.rb +1 -1
  15. data/lib/pact_broker/versions/repository.rb +4 -0
  16. data/lib/pact_broker/versions/service.rb +7 -1
  17. data/lib/rack/pact_broker/database_transaction.rb +42 -0
  18. data/lib/rack/pact_broker/invalid_uri_protection.rb +36 -0
  19. data/pact_broker.gemspec +1 -0
  20. data/script/publish-new.sh +3 -1
  21. data/script/recreate-pg-db.sh +1 -0
  22. data/spec/features/delete_version_spec.rb +23 -0
  23. data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +1 -1
  24. data/spec/lib/pact_broker/api/decorators/webhook_decorator_spec.rb +3 -3
  25. data/spec/lib/pact_broker/api/decorators/webhooks_decorator_spec.rb +3 -3
  26. data/spec/lib/pact_broker/app_spec.rb +35 -1
  27. data/spec/lib/pact_broker/domain/order_versions_spec.rb +22 -0
  28. data/spec/lib/pact_broker/pacts/repository_spec.rb +23 -0
  29. data/spec/lib/pact_broker/tags/repository_spec.rb +22 -1
  30. data/spec/lib/pact_broker/versions/repository_spec.rb +16 -0
  31. data/spec/lib/pact_broker/versions/service_spec.rb +35 -0
  32. data/spec/lib/rack/pact_broker/database_transaction_spec.rb +45 -0
  33. data/spec/lib/rack/pact_broker/invalid_uri_protection_spec.rb +30 -0
  34. data/spec/spec_helper.rb +2 -1
  35. metadata +28 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22d05f1fc364395a7232c0f95a4566816533c476
4
- data.tar.gz: acd6dbb2fc0f05ba3cfe47029b187435213fa5bb
3
+ metadata.gz: 880db0a792e03e1d623978995043fd1658e9674e
4
+ data.tar.gz: 0dca6bd356860e3392292b10bc3c23d18f51cd65
5
5
  SHA512:
6
- metadata.gz: 4c70846fdbdff418c6a9f231384e8796cabc7003b4b8d631ebac9b6e9a306f7f6b9a48b4adf45fd49e471d5b8e5260609401b4581a806de0edbcedaa37b995a5
7
- data.tar.gz: 7d9c77cda110fea93028b43ca5e7f489e8258b2f6132a6b6eb964d34af8267547a064b51f2d4118eddca2571b165e97282f9b97623a2c71301b66a4cba8d9693
6
+ metadata.gz: 2eab4b5d78400d982467ccd00f9e1e382a99cc145ee02d6721147a91de925f67f97c4a9cf3d998cef126ab73b1f41a85e308d64f5743aa8eef76b846052adf92
7
+ data.tar.gz: 9cd39079ca7a9ff6a595aee30933fd74dbc3c899a3fb65daf9522c040fa8a5979ccb3c5f2c295a3f7398c85d7010987812c24b43bd53aafe967690fbfe0dc238
@@ -2,6 +2,13 @@ Do this to generate your change history
2
2
 
3
3
  $ git log --pretty=format:' * %h - %s (%an, %ad)' vX.Y.Z..HEAD
4
4
 
5
+ #### 2.0.1 (2017-05-17)
6
+ * 8d105aa - Allow an application version to be deleted via the API. (Beth Skurrie, Fri May 19 10:39:16 2017 +1000)
7
+ * 025b0f7 - Ensure version numbers that don't conform to the semver2 spec don't cause errors when sorting versions. #103 (Beth Skurrie, Fri May 19 09:58:50 2017 +1000)
8
+ * ca6d88e - Corrected hal link rels that had missing curies (prepended "pb:") (Beth Skurrie, Thu May 18 10:20:06 2017 +1000)
9
+ * 1cabd5e - Use Rack::Protection. (Beth Skurrie, Tue May 16 10:13:40 2017 +1000)
10
+ * 2a3bbd1 - Return 404 instead of 500 when Ruby standard URI lib can't parse the URI. https://github.com/pact-foundation/pact_broker/issues/101 (Beth Skurrie, Tue May 16 09:45:37 2017 +1000)
11
+
5
12
  #### 2.0.0 (2017-05-16)
6
13
 
7
14
  #### 2.0.0.beta.8 (2017-05-15)
@@ -25,7 +25,7 @@ module PactBroker
25
25
  }
26
26
  end
27
27
 
28
- link :pacticipant do | options |
28
+ link :'pb:pacticipant' do | options |
29
29
  {
30
30
  title: 'Pacticipant',
31
31
  name: represented.pacticipant.name,
@@ -24,21 +24,21 @@ module PactBroker
24
24
 
25
25
  end
26
26
 
27
- link :'pact-webhooks' do | options |
27
+ link :'pb:pact-webhooks' do | options |
28
28
  {
29
29
  title: "All webhooks for the pact between #{represented.consumer.name} and #{represented.provider.name}",
30
30
  href: webhooks_for_pact_url(represented.consumer, represented.provider, options[:base_url])
31
31
  }
32
32
  end
33
33
 
34
- link :'webhooks' do | options |
34
+ link :'pb:webhooks' do | options |
35
35
  {
36
36
  title: "All webhooks",
37
37
  href: webhooks_url(options[:base_url])
38
38
  }
39
39
  end
40
40
 
41
- link :execute do | options |
41
+ link :'pb:execute' do | options |
42
42
  {
43
43
  title: "Test the execution of the webhook by sending a POST request to this URL",
44
44
  href: webhook_execution_url(represented, options[:base_url])
@@ -14,7 +14,14 @@ module PactBroker
14
14
  }
15
15
  end
16
16
 
17
- links :webhooks do | context |
17
+ link :'pb:create' do | context |
18
+ {
19
+ title: "POST to create a webhook",
20
+ href: context[:resource_url]
21
+ }
22
+ end
23
+
24
+ links :'pb:webhooks' do | context |
18
25
  represented.entries.collect do | webhook |
19
26
  {
20
27
  title: webhook.description,
@@ -27,7 +34,8 @@ module PactBroker
27
34
  curies do | context |
28
35
  [{
29
36
  name: :pb,
30
- href: context[:base_url] + '/doc/webhooks',
37
+ href: context[:base_url] + '/doc/webhooks-{rel}',
38
+ templated: true
31
39
  }]
32
40
  end
33
41
 
@@ -12,7 +12,7 @@ module PactBroker
12
12
  end
13
13
 
14
14
  def allowed_methods
15
- ["GET"]
15
+ ["GET", "DELETE"]
16
16
  end
17
17
 
18
18
  def resource_exists?
@@ -23,6 +23,11 @@ module PactBroker
23
23
  Decorators::VersionDecorator.new(version).to_json(user_options: {base_url: base_url})
24
24
  end
25
25
 
26
+ def delete_resource
27
+ version_service.delete version
28
+ true
29
+ end
30
+
26
31
  private
27
32
 
28
33
  def version
@@ -1,9 +1,12 @@
1
1
  require 'pact_broker/configuration'
2
2
  require 'pact_broker/db'
3
3
  require 'pact_broker/project_root'
4
+ require 'rack-protection'
4
5
  require 'rack/hal_browser'
5
6
  require 'rack/pact_broker/add_pact_broker_version_header'
6
7
  require 'rack/pact_broker/convert_file_extension_to_accept_header'
8
+ require 'rack/pact_broker/database_transaction'
9
+ require 'rack/pact_broker/invalid_uri_protection'
7
10
  require 'sucker_punch'
8
11
 
9
12
  module PactBroker
@@ -54,6 +57,8 @@ module PactBroker
54
57
  def build_app
55
58
  @app = Rack::Builder.new
56
59
 
60
+ @app.use Rack::Protection, except: [:remote_token, :session_hijacking]
61
+ @app.use Rack::PactBroker::InvalidUriProtection
57
62
  @app.use Rack::PactBroker::AddPactBrokerVersionHeader
58
63
  @app.use Rack::Static, :urls => ["/stylesheets", "/css", "/fonts", "/js", "/javascripts", "/images"], :root => PactBroker.project_root.join("public")
59
64
  @app.use Rack::PactBroker::ConvertFileExtensionToAcceptHeader
@@ -79,7 +84,7 @@ module PactBroker
79
84
  end
80
85
 
81
86
  apps << PactBroker::UI::App.new
82
- apps << PactBroker::API
87
+ apps << Rack::PactBroker::DatabaseTransaction.new(PactBroker::API, configuration.database_connection)
83
88
 
84
89
  @app.map "/" do
85
90
  run Rack::Cascade.new(apps)
@@ -0,0 +1,38 @@
1
+ # Create a webhook
2
+
3
+ Allowed methods: POST
4
+
5
+ 1. Click the "NON-GET" button for the "pb:create" relation.
6
+ 3. Paste in the webhook JSON (example shown below) in the body section and click "Make Request".
7
+
8
+ An example webhook to trigger a Bamboo job.
9
+
10
+ {
11
+ "request": {
12
+ "method": "POST",
13
+ "url": "http://master.ci.my.domain:8085/rest/api/latest/queue/SOME-PROJECT?os_authType=basic",
14
+ "username": "username",
15
+ "password": "password",
16
+ "headers": {
17
+ "Accept": "application/json"
18
+ }
19
+ }
20
+ }
21
+
22
+ A request body can be specified as well.
23
+
24
+ {
25
+ "request": {
26
+ "method": "POST",
27
+ "url": "http://example.org/something",
28
+ "body": {
29
+ "some" : "json"
30
+ }
31
+ }
32
+ }
33
+
34
+ **BEWARE** The password can be reverse engineered from the database, so make a separate account for the Pact Broker to use, don't use your personal account!
35
+
36
+ ### Testing
37
+
38
+ To test a webhook, navigate to the webhook in the HAL browser, then make a POST request to the "execute" relation. The response or error will be shown in the window.
@@ -0,0 +1,15 @@
1
+ # Webhooks
2
+
3
+ Allowed methods: GET, DELETE
4
+
5
+ ### Testing
6
+
7
+ To test a webhook, navigate to the webhook in the HAL browser, then make a POST request to the "execute" relation. The response or error will be shown in the window.
8
+
9
+ ### Deleting
10
+
11
+ Send a DELETE request to the webhook URL.
12
+
13
+ ### Updating
14
+
15
+ Currently not implemented. You will need to delete and re-create the webhook.
@@ -26,8 +26,22 @@ module PactBroker
26
26
  @sortable_number = PactBroker.configuration.version_parser.call version_model.number
27
27
  end
28
28
 
29
+ # Incoming version numbers are rejected if they can't be parsed by the version parser,
30
+ # however, the change from Versionomy to SemVer for version parsing means that some
31
+ # existing version numbers cannot be parsed and are returning nil.
32
+ # The main reason to sort the versions is to that we can get the "latest" pact.
33
+ # Any existing version with a number that cannot be parsed will almost definitely not
34
+ # be the "latest", so sort them first.
29
35
  def <=> other
30
- self.sortable_number <=> other.sortable_number
36
+ if sortable_number.nil? && other.sortable_number.nil?
37
+ 0
38
+ elsif sortable_number.nil?
39
+ -1
40
+ elsif other.sortable_number.nil?
41
+ 1
42
+ else
43
+ self.sortable_number <=> other.sortable_number
44
+ end
31
45
  end
32
46
 
33
47
  def update_model new_order
@@ -75,15 +75,17 @@ module PactBroker
75
75
  def self.delete name
76
76
  pacticipant = find_pacticipant_by_name name
77
77
  connection = PactBroker::Domain::Pacticipant.new.db
78
+ version_ids = PactBroker::Domain::Version.where(pacticipant_id: pacticipant.id).select(:id)
78
79
  select_pacticipant = "select id from pacticipants where name = '#{name}'"
79
- connection.run("delete from tags where version_id IN (select id from versions where pacticipant_id = #{pacticipant.id})")
80
- connection.run("delete from pact_publications where consumer_version_id IN (select id from versions where pacticipant_id = #{pacticipant.id})")
80
+ tag_repository.delete_by_version_id version_ids
81
+ pact_repository.delete_by_version_id version_ids
81
82
  connection.run("delete from pact_publications where provider_id = #{pacticipant.id}")
82
83
  connection.run("delete from verifications where pact_version_id IN (select id from pact_versions where provider_id = #{pacticipant.id})")
83
84
  connection.run("delete from verifications where pact_version_id IN (select id from pact_versions where consumer_id = #{pacticipant.id})")
84
85
  connection.run("delete from pact_versions where provider_id = #{pacticipant.id}")
85
86
  connection.run("delete from pact_versions where consumer_id = #{pacticipant.id}")
86
87
  connection.run("delete from versions where pacticipant_id = #{pacticipant.id}")
88
+ version_repository.delete_by_id version_ids
87
89
  webhook_service.delete_by_pacticipant pacticipant
88
90
  connection.run("delete from pacticipants where id = #{pacticipant.id}")
89
91
  end
@@ -48,6 +48,10 @@ module PactBroker
48
48
  PactPublication.where(id: id).delete
49
49
  end
50
50
 
51
+ def delete_by_version_id version_id
52
+ Sequel::Model.db[:pact_publications].where(consumer_version_id: version_id).delete
53
+ end
54
+
51
55
  def find_all_pact_versions_between consumer_name, options
52
56
  provider_name = options.fetch(:and)
53
57
  LatestPactPublicationsByConsumerVersion
@@ -22,6 +22,10 @@ module PactBroker
22
22
  .where(name_like(Sequel.qualify("pacticipants", "name"), args.fetch(:pacticipant_name)))
23
23
  .single_record
24
24
  end
25
+
26
+ def delete_by_version_id version_id
27
+ Sequel::Model.db[:tags].where(version_id: version_id).delete
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.0.0'
2
+ VERSION = '2.0.1'
3
3
  end
@@ -34,6 +34,10 @@ module PactBroker
34
34
  create(pacticipant_id: pacticipant_id, number: number)
35
35
  end
36
36
  end
37
+
38
+ def delete_by_id version_ids
39
+ Sequel::Model.db[:versions].where(id: version_ids).delete
40
+ end
37
41
  end
38
42
  end
39
43
  end
@@ -10,6 +10,12 @@ module PactBroker
10
10
  def self.find_by_pacticipant_name_and_number params
11
11
  version_repository.find_by_pacticipant_name_and_number params.fetch(:pacticipant_name), params.fetch(:pacticipant_version_number)
12
12
  end
13
+
14
+ def self.delete version
15
+ tag_repository.delete_by_version_id version.id
16
+ pact_repository.delete_by_version_id version.id
17
+ version_repository.delete_by_id version.id
18
+ end
13
19
  end
14
20
  end
15
- end
21
+ end
@@ -0,0 +1,42 @@
1
+ require 'pact_broker/version'
2
+ require 'sequel'
3
+
4
+ module Rack
5
+ module PactBroker
6
+ class DatabaseTransaction
7
+
8
+ REQUEST_METHOD = "REQUEST_METHOD".freeze
9
+ TRANS_METHODS = %{POST PUT PATCH DELETE}.freeze
10
+
11
+ def initialize app, database_connection
12
+ @app = app
13
+ @database_connection = database_connection
14
+ end
15
+
16
+ def call env
17
+ if use_transaction? env
18
+ call_with_transaction env
19
+ else
20
+ call_without_transaction env
21
+ end
22
+ end
23
+
24
+ def use_transaction? env
25
+ TRANS_METHODS.include? env[REQUEST_METHOD]
26
+ end
27
+
28
+ def call_without_transaction env
29
+ @app.call(env)
30
+ end
31
+
32
+ def call_with_transaction env
33
+ response = nil
34
+ @database_connection.transaction do
35
+ response = @app.call(env)
36
+ raise Sequel::Rollback if response.first == 500
37
+ end
38
+ response
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,36 @@
1
+ require 'uri'
2
+
3
+ # This class is for https://github.com/pact-foundation/pact_broker/issues/101
4
+ # curl -i "http://127.0.0.1:9292/<script>"
5
+
6
+ module Rack
7
+ module PactBroker
8
+ class InvalidUriProtection
9
+
10
+ def initialize app
11
+ @app = app
12
+ end
13
+
14
+ def call env
15
+ if valid_uri? env
16
+ @app.call(env)
17
+ else
18
+ [404, {}, []]
19
+ end
20
+ end
21
+
22
+ def valid_uri? env
23
+ begin
24
+ parse(::Rack::Request.new(env).url)
25
+ true
26
+ rescue URI::InvalidURIError
27
+ false
28
+ end
29
+ end
30
+
31
+ def parse uri
32
+ URI.parse(uri)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -36,6 +36,7 @@ Gem::Specification.new do |gem|
36
36
  gem.add_runtime_dependency 'padrino-core', '~>0.12.4'
37
37
  gem.add_runtime_dependency 'haml', '~>4.0'
38
38
  gem.add_runtime_dependency 'sucker_punch', '~>2.0'
39
+ gem.add_runtime_dependency 'rack-protection', '~>1.5'
39
40
 
40
41
  gem.add_development_dependency 'sqlite3'
41
42
  gem.add_development_dependency 'pry-byebug'
@@ -1,7 +1,9 @@
1
1
  # set -x
2
2
  BODY=$(ruby -e "require 'json'; j = JSON.parse(File.read('script/foo-bar.json')); j['interactions'][0]['providerState'] = 'it is ' + Time.now.to_s; puts j.to_json")
3
+ latest_url=$(curl http://localhost:9292/pacts/provider/Bar/consumer/Foo/latest | jq -r ._links.self.href)
4
+ next_version=$(echo ${latest_url} | ruby -e "require 'semver'; puts SemVer.parse(ARGF.read[/\d+\.\d\.\d+/]).tap{ | v| v.minor = v.minor + 1}.format('%M.%m.%p')")
3
5
  echo ${BODY} >> tmp.json
4
6
  curl -v -XPUT \-H "Content-Type: application/json" \
5
7
  -d@tmp.json \
6
- http://127.0.0.1:9292/pacts/provider/Bar/consumer/Foo/version/1.0.0
8
+ http://127.0.0.1:9292/pacts/provider/Bar/consumer/Foo/version/${next_version}
7
9
  rm tmp.json
@@ -1,3 +1,4 @@
1
+ set -e
1
2
  psql postgres -c "DROP DATABASE pact_broker;"
2
3
  psql postgres -c "CREATE DATABASE pact_broker;"
3
4
  psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE pact_broker TO pact_broker;"
@@ -0,0 +1,23 @@
1
+ require 'spec/support/provider_state_builder'
2
+
3
+ describe "Delete version" do
4
+
5
+ let(:path) { "/pacticipants/Consumer/versions/1.2.3" }
6
+ let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
7
+
8
+ subject { delete path; last_response }
9
+
10
+ before do
11
+ ProviderStateBuilder.new
12
+ .create_consumer("Another Consumer")
13
+ .create_consumer("Consumer")
14
+ .create_consumer_version("1.2.3")
15
+ .create_consumer_version_tag("prod")
16
+ .create_consumer_version("1.2.4")
17
+ end
18
+
19
+
20
+ it "returns a 200 HAL JSON response" do
21
+ expect(subject.status).to eq 204
22
+ end
23
+ end
@@ -35,7 +35,7 @@ module PactBroker
35
35
  end
36
36
 
37
37
  it "includes a link to the pacticipant" do
38
- expect(subject[:_links][:pacticipant]).to eq title: "Pacticipant", name: "Consumer", href: "http://example.org/pacticipants/Consumer"
38
+ expect(subject[:_links][:'pb:pacticipant']).to eq title: "Pacticipant", name: "Consumer", href: "http://example.org/pacticipants/Consumer"
39
39
  end
40
40
 
41
41
  it "includes a list of the tags" do
@@ -72,15 +72,15 @@ module PactBroker
72
72
  end
73
73
 
74
74
  it 'includes a link to its parent collection' do
75
- expect(parsed_json[:_links][:'pact-webhooks'][:href]).to_not be_nil
75
+ expect(parsed_json[:_links][:'pb:pact-webhooks'][:href]).to_not be_nil
76
76
  end
77
77
 
78
78
  it 'includes a link to the webhooks resource' do
79
- expect(parsed_json[:_links][:webhooks][:href]).to_not be_nil
79
+ expect(parsed_json[:_links][:'pb:webhooks'][:href]).to_not be_nil
80
80
  end
81
81
 
82
82
  it 'includes a link to execute the webhook directly' do
83
- expect(parsed_json[:_links][:execute][:href]).to eq 'http://example.org/webhooks/some-uuid/execute'
83
+ expect(parsed_json[:_links][:'pb:execute'][:href]).to eq 'http://example.org/webhooks/some-uuid/execute'
84
84
  end
85
85
 
86
86
  it 'includes timestamps' do
@@ -30,12 +30,12 @@ module PactBroker
30
30
  end
31
31
 
32
32
  it "includes a list of links to the webhooks" do
33
- expect(subject[:_links][:webhooks]).to be_instance_of(Array)
34
- expect(subject[:_links][:webhooks].first).to eq title: 'description', name: 'request description', href: 'http://example.org/webhooks/some-uuid'
33
+ expect(subject[:_links][:'pb:webhooks']).to be_instance_of(Array)
34
+ expect(subject[:_links][:'pb:webhooks'].first).to eq title: 'description', name: 'request description', href: 'http://example.org/webhooks/some-uuid'
35
35
  end
36
36
 
37
37
  it "includes curies" do
38
- expect(subject[:_links][:curies]).to eq [{:name=>"pb", :href=>"http://example.org/doc/webhooks"}]
38
+ expect(subject[:_links][:curies]).to eq [{:name=>"pb", :href=>"http://example.org/doc/webhooks-{rel}", templated: true}]
39
39
  end
40
40
 
41
41
  end
@@ -3,9 +3,22 @@ require 'pact_broker/app'
3
3
  module PactBroker
4
4
  describe App do
5
5
 
6
+ class TestApp < PactBroker::App
7
+
8
+ def configure_database_connection
9
+ # do nothing
10
+ end
11
+
12
+ def post_configure
13
+ # do nothing
14
+ end
15
+
16
+ end
17
+
6
18
  let(:app) do
7
- PactBroker::App.new do | configuration |
19
+ TestApp.new do | configuration |
8
20
  configuration.database_connection = PactBroker::DB.connection
21
+ configuration.auto_migrate_db = false
9
22
  end
10
23
  end
11
24
 
@@ -14,5 +27,26 @@ module PactBroker
14
27
  expect(last_response.headers['X-Pact-Broker-Version']).to match /\d/
15
28
  end
16
29
 
30
+ describe "transactions", no_db_clean: true do
31
+ let(:pact_content) { load_fixture('a_consumer-a_provider.json') }
32
+ let(:path) { "/pacts/provider/A%20Provider/consumer/A%20Consumer/versions/1.2.3" }
33
+ let(:response_body_json) { JSON.parse(subject.body) }
34
+
35
+ before do
36
+ PactBroker::Database.truncate
37
+ allow_any_instance_of(PactBroker::Pacts::Repository).to receive(:create).and_raise("an error")
38
+ end
39
+
40
+ after do
41
+ PactBroker::Database.truncate
42
+ end
43
+
44
+ subject { put path, pact_content, {'CONTENT_TYPE' => 'application/json' }; last_response }
45
+
46
+ it "wraps the API with a database transaction" do
47
+ expect { subject }.to_not change { PactBroker::Domain::Pacticipant.count }
48
+ end
49
+ end
50
+
17
51
  end
18
52
  end
@@ -40,4 +40,26 @@ describe PactBroker::Domain::OrderVersions do
40
40
 
41
41
  end
42
42
 
43
+ context "when an existing version number in the database that Versionomy could parse cannot be parsed by SemVer" do
44
+ let!(:consumer) do
45
+ ProviderStateBuilder.new
46
+ .create_consumer
47
+ .create_consumer_version('1')
48
+ .create_consumer_version('2')
49
+ .create_consumer_version('3')
50
+ .create_consumer_version('4')
51
+ .and_return(:consumer)
52
+ end
53
+
54
+ let(:ordered_versions) { PactBroker::Domain::Version.order(:order).all.collect(&:number) }
55
+
56
+ it "sorts the unparseable version as being first and maintains their relative order" do
57
+ Sequel::Model.db[:versions].where(number: '1').update(number: 'z')
58
+ Sequel::Model.db[:versions].where(number: '2').update(number: 'a')
59
+ Sequel::Model.db[:versions].where(number: '4').update(number: 'h')
60
+ PactBroker::Domain::Version.create(number: '5', pacticipant_id: consumer.id)
61
+ expect(ordered_versions).to eq(['z', 'a', 'h', '3', '5'])
62
+ end
63
+ end
64
+
43
65
  end
@@ -191,6 +191,29 @@ module PactBroker
191
191
 
192
192
  end
193
193
 
194
+ describe "delete_by_version_id" do
195
+ let!(:version) do
196
+ ProviderStateBuilder.new
197
+ .create_consumer
198
+ .create_provider
199
+ .create_consumer_version("4.5.6")
200
+ .create_pact
201
+ .create_consumer_version("1.2.3")
202
+ .create_pact
203
+ .and_return(:consumer_version)
204
+ end
205
+
206
+ subject { Repository.new.delete_by_version_id(version.id) }
207
+
208
+ it "deletes the pact publication" do
209
+ expect{ subject }.to change { PactPublication.count }.by(-1)
210
+ end
211
+
212
+ it "does not delete the content because it may be used by another pact" do
213
+ expect { subject }.to change { PactVersion.count }.by(0)
214
+ end
215
+ end
216
+
194
217
  describe "#find_all_pact_versions_between" do
195
218
 
196
219
  before do
@@ -62,6 +62,27 @@ module PactBroker
62
62
  end
63
63
  end
64
64
 
65
+ describe "delete_by_version_id" do
66
+ let!(:version) do
67
+ ProviderStateBuilder.new
68
+ .create_consumer
69
+ .create_provider
70
+ .create_consumer_version("4.5.6")
71
+ .create_consumer_version_tag("prod")
72
+ .create_consumer_version("1.2.3")
73
+ .create_consumer_version_tag("prod")
74
+ .create_consumer_version_tag("foo")
75
+ .and_return(:consumer_version)
76
+ end
77
+
78
+ subject { Repository.new.delete_by_version_id(version.id) }
79
+
80
+ it "deletes the tag" do
81
+ expect{ subject }.to change { PactBroker::Domain::Tag.count }.by(-2)
82
+ end
83
+
84
+ end
85
+
65
86
  end
66
87
  end
67
- end
88
+ end
@@ -24,6 +24,22 @@ module PactBroker
24
24
  end
25
25
  end
26
26
 
27
+ describe "#delete_by_id" do
28
+ let!(:version) do
29
+ ProviderStateBuilder.new
30
+ .create_consumer
31
+ .create_consumer_version("1.2.3")
32
+ .create_consumer_version("4.5.6")
33
+ .and_return(:consumer_version)
34
+ end
35
+
36
+ subject { Repository.new.delete_by_id version.id }
37
+
38
+ it "deletes the version" do
39
+ expect { subject }.to change{ PactBroker::Domain::Version.count }.by(-1)
40
+ end
41
+ end
42
+
27
43
  describe "#find_by_pacticipant_name_and_number" do
28
44
 
29
45
  subject { described_class.new.find_by_pacticipant_name_and_number pacticipant_name, version_number }
@@ -0,0 +1,35 @@
1
+ require 'pact_broker/versions/service'
2
+
3
+ module PactBroker
4
+
5
+ module Versions
6
+ describe Service do
7
+
8
+ describe ".delete" do
9
+ let!(:version) do
10
+ ProviderStateBuilder.new
11
+ .create_consumer
12
+ .create_provider
13
+ .create_consumer_version("1.2.3")
14
+ .create_consumer_version_tag("prod")
15
+ .create_pact
16
+ .and_return(:consumer_version)
17
+ end
18
+
19
+ subject { Service.delete(version) }
20
+
21
+ it "deletes the pact publication" do
22
+ expect{ subject }.to change { PactBroker::Pacts::PactPublication.count }.by(-1)
23
+ end
24
+
25
+ it "deletes the tags" do
26
+ expect{ subject }.to change { PactBroker::Domain::Tag.count }.by(-1)
27
+ end
28
+
29
+ it "deletes the version" do
30
+ expect{ subject }.to change { PactBroker::Domain::Version.count }.by(-1)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ require 'tasks/database'
2
+ require 'rack/pact_broker/database_transaction'
3
+
4
+ module Rack
5
+ module PactBroker
6
+ describe DatabaseTransaction, no_db_clean: true do
7
+
8
+ before do
9
+ ::PactBroker::Database.truncate
10
+ end
11
+
12
+ after do
13
+ ::PactBroker::Database.truncate
14
+ end
15
+
16
+ let(:api) do
17
+ ->(env) { ::PactBroker::Domain::Pacticipant.create(name: 'Foo'); [500, {}, []] }
18
+ end
19
+
20
+ let(:api_with_transaction) do
21
+ ::Rack::PactBroker::DatabaseTransaction.new(api, ::PactBroker::DB.connection)
22
+ end
23
+
24
+ subject { self.send(http_method, "/") }
25
+
26
+ context "for get requests" do
27
+ let(:app) { api_with_transaction }
28
+
29
+ let(:http_method) { :get }
30
+ it "does not use a transaction" do
31
+ expect { subject }.to change { ::PactBroker::Domain::Pacticipant.count }.by(1)
32
+ end
33
+ end
34
+
35
+ [:post, :put, :patch, :delete].each do | http_meth |
36
+ let(:http_method) { http_meth }
37
+ context "for #{http_meth} requests" do
38
+ it "uses a transaction and rollsback if there is a 500 error" do
39
+ expect { subject }.to change { ::PactBroker::Domain::Pacticipant.count }.by(0)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ require 'rack/pact_broker/invalid_uri_protection'
2
+
3
+ module Rack
4
+ module PactBroker
5
+ describe InvalidUriProtection do
6
+
7
+ let(:app) { InvalidUriProtection.new(->(env){ [200,{},[]] }) }
8
+
9
+ subject { get "/badpath"; last_response }
10
+
11
+ context "with a URI that the Ruby default URI library cannot parse" do
12
+
13
+ before do
14
+ # Can't use or stub URI.parse because rack test uses it to execute the actual test
15
+ allow_any_instance_of(InvalidUriProtection).to receive(:parse).and_raise(URI::InvalidURIError)
16
+ end
17
+
18
+ it "returns a 404" do
19
+ expect(subject.status).to eq 404
20
+ end
21
+ end
22
+
23
+ context "when the URI can be parsed" do
24
+ it "passes the request to the underlying app" do
25
+ expect(subject.status).to eq 200
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -5,6 +5,7 @@ $: << File.expand_path("../../", __FILE__)
5
5
  require 'rack/test'
6
6
  require 'db'
7
7
  require 'pact_broker/api'
8
+ require 'tasks/database'
8
9
  require 'rspec/its'
9
10
 
10
11
  Dir.glob("./spec/support/**/*.rb") { |file| require file }
@@ -14,7 +15,7 @@ I18n.config.enforce_available_locales = false
14
15
  RSpec.configure do | config |
15
16
  config.before :suite do
16
17
  raise "Wrong environment!!! Don't run this script!! ENV['RACK_ENV'] is #{ENV['RACK_ENV']} and RACK_ENV is #{RACK_ENV}" if ENV['RACK_ENV'] != 'test' || RACK_ENV != 'test'
17
- PactBroker::DB.connection = DB::PACT_BROKER_DB
18
+ PactBroker::DB.connection = PactBroker::Database.database = DB::PACT_BROKER_DB
18
19
  end
19
20
 
20
21
  config.include Rack::Test::Methods
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-05-15 00:00:00.000000000 Z
13
+ date: 2017-05-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -234,6 +234,20 @@ dependencies:
234
234
  - - "~>"
235
235
  - !ruby/object:Gem::Version
236
236
  version: '2.0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: rack-protection
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: '1.5'
244
+ type: :runtime
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - "~>"
249
+ - !ruby/object:Gem::Version
250
+ version: '1.5'
237
251
  - !ruby/object:Gem::Dependency
238
252
  name: sqlite3
239
253
  requirement: !ruby/object:Gem::Requirement
@@ -534,6 +548,8 @@ files:
534
548
  - lib/pact_broker/doc/views/self.markdown
535
549
  - lib/pact_broker/doc/views/tag-prod-version.markdown
536
550
  - lib/pact_broker/doc/views/tag-version.markdown
551
+ - lib/pact_broker/doc/views/webhooks-create.markdown
552
+ - lib/pact_broker/doc/views/webhooks-webhooks.markdown
537
553
  - lib/pact_broker/doc/views/webhooks.markdown
538
554
  - lib/pact_broker/domain.rb
539
555
  - lib/pact_broker/domain/group.rb
@@ -607,6 +623,8 @@ files:
607
623
  - lib/rack/hal_browser/redirect.rb
608
624
  - lib/rack/pact_broker/add_pact_broker_version_header.rb
609
625
  - lib/rack/pact_broker/convert_file_extension_to_accept_header.rb
626
+ - lib/rack/pact_broker/database_transaction.rb
627
+ - lib/rack/pact_broker/invalid_uri_protection.rb
610
628
  - pact_broker.gemspec
611
629
  - pact_broker_client-pact_broker.json
612
630
  - public/Network Graph_files/d3.v3.js
@@ -643,6 +661,7 @@ files:
643
661
  - script/update-hal-browser
644
662
  - spec/features/create_webhook_spec.rb
645
663
  - spec/features/delete_pact_spec.rb
664
+ - spec/features/delete_version_spec.rb
646
665
  - spec/features/get_diff_spec.rb
647
666
  - spec/features/get_pact_spec.rb
648
667
  - spec/features/get_pact_versions_spec.rb
@@ -744,11 +763,14 @@ files:
744
763
  - spec/lib/pact_broker/verifications/summary_for_consumer_version_spec.rb
745
764
  - spec/lib/pact_broker/versions/parse_semantic_version_spec.rb
746
765
  - spec/lib/pact_broker/versions/repository_spec.rb
766
+ - spec/lib/pact_broker/versions/service_spec.rb
747
767
  - spec/lib/pact_broker/webhooks/job_spec.rb
748
768
  - spec/lib/pact_broker/webhooks/repository_spec.rb
749
769
  - spec/lib/pact_broker/webhooks/service_spec.rb
750
770
  - spec/lib/rack/hal_browser/redirect_spec.rb
751
771
  - spec/lib/rack/pact_broker/add_pact_broker_version_header_spec.rb
772
+ - spec/lib/rack/pact_broker/database_transaction_spec.rb
773
+ - spec/lib/rack/pact_broker/invalid_uri_protection_spec.rb
752
774
  - spec/migrations/23_pact_versions_spec.rb
753
775
  - spec/migrations/24_populate_pact_contents_spec.rb
754
776
  - spec/migrations/34_latest_tagged_pacts_spec.rb
@@ -830,6 +852,7 @@ summary: See description
830
852
  test_files:
831
853
  - spec/features/create_webhook_spec.rb
832
854
  - spec/features/delete_pact_spec.rb
855
+ - spec/features/delete_version_spec.rb
833
856
  - spec/features/get_diff_spec.rb
834
857
  - spec/features/get_pact_spec.rb
835
858
  - spec/features/get_pact_versions_spec.rb
@@ -931,11 +954,14 @@ test_files:
931
954
  - spec/lib/pact_broker/verifications/summary_for_consumer_version_spec.rb
932
955
  - spec/lib/pact_broker/versions/parse_semantic_version_spec.rb
933
956
  - spec/lib/pact_broker/versions/repository_spec.rb
957
+ - spec/lib/pact_broker/versions/service_spec.rb
934
958
  - spec/lib/pact_broker/webhooks/job_spec.rb
935
959
  - spec/lib/pact_broker/webhooks/repository_spec.rb
936
960
  - spec/lib/pact_broker/webhooks/service_spec.rb
937
961
  - spec/lib/rack/hal_browser/redirect_spec.rb
938
962
  - spec/lib/rack/pact_broker/add_pact_broker_version_header_spec.rb
963
+ - spec/lib/rack/pact_broker/database_transaction_spec.rb
964
+ - spec/lib/rack/pact_broker/invalid_uri_protection_spec.rb
939
965
  - spec/migrations/23_pact_versions_spec.rb
940
966
  - spec/migrations/24_populate_pact_contents_spec.rb
941
967
  - spec/migrations/34_latest_tagged_pacts_spec.rb