Skip to content

Commit 1eb7caf

Browse files
committed
test: improved db backwards compatiblity tests
Discovered that 2.0.0 -> 2.1.0 db/code is not backwards compatible, and updated the documentation to reflect that
1 parent 7ccbfa2 commit 1eb7caf

File tree

7 files changed

+109
-39
lines changed

7 files changed

+109
-39
lines changed

UPGRADING.md

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# Upgrading from a previous version of the Pact Broker
22

3-
## Pact Broker versions >= 2.0.0
3+
## Pact Broker versions >= 2.1.0
44

5-
Backwards compatibility for database migrations in relation to the codebase will be supported according to semantic versioning (ie. any backwards incompatible changes will be done in major releases). This means that zero downtime deployments using rolling upgrades for setups with multiple HTTP servers sharing the same database are supported between any 2 versions within the same major release.
5+
Backwards compatibility tests will ensure that the latest version of the database will be compatible with a previous version of the code until v3.0.0 for the following endpoints:
66

7-
A migration path will be provided for major releases to allow zero downtime deployments, and will be documented here.
7+
* Tag version
8+
* Publish pact
9+
* Retrieve latest pact
10+
* Retrieve latest pact for tag
811

9-
## Pact Broker < 2.0.0
12+
This means that zero downtime rolling upgrades for architectures that use multiple web servers (eg. Amazon autoscaling groups) are supported between any two versions from 2.1.0.
1013

11-
The upgrade between 1.18.0 and 2.0.0 contains database migrations that are NOT backwards compatible. It is recommended to run a single instance of the broker while performing an upgrade that traverses these versions.
14+
When backwards-incompatible changes need to be made in the future, a zero downtime upgrade path will documented on this page.
15+
16+
## Pact Broker < 2.1.0
17+
18+
The upgrades between 1.18.0 and 2.1.0 contains database migrations that are NOT backwards compatible with previous versions of the code. It is recommended to run a single instance of the broker while performing an upgrade that traverses these versions.

db/test/backwards_compatibility/Rakefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ TESTS = [
66
%w{2.4.2 9296},
77
%w{2.3.0 9295},
88
%w{2.2.0 9294},
9-
%w{2.1.0 9293},
10-
%w{2.0.0 9292}
9+
%w{2.1.0 9293}
1110
]
11+
1212
DATABASE_VERSION = TESTS.first.first
1313

1414
def start_pact_broker code_version, port
@@ -28,6 +28,7 @@ def clean
2828
FileUtils.rm_rf 'pids'
2929
FileUtils.mkdir 'pids'
3030
FileUtils.rm_rf 'pact_broker_database.sqlite3'
31+
FileUtils.rm_rf 'log'
3132
end
3233

3334
RSpec::Core::RakeTask.new(:spec) do |task|

db/test/backwards_compatibility/config.ru

+2
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ app = PactBroker::App.new do | config |
1313
config.auto_migrate_db = true
1414
end
1515

16+
PactBroker.logger.info "Running PactBroker #{PactBroker::VERSION}"
17+
1618
run app

db/test/backwards_compatibility/spec/publish_pact_spec.rb

+54-31
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,69 @@
11
require 'rack/reverse_proxy'
2+
require 'securerandom'
23

3-
code_version = ENV.fetch('PACT_BROKER_CODE_VERSION')
4-
database_version = ENV.fetch('PACT_BROKER_DATABASE_VERSION')
5-
6-
describe "Code version #{code_version} running against database version #{database_version}" do
7-
describe "Publishing a pact" do
8-
9-
before do
10-
unless ENV['OK']
11-
retries = 0
12-
begin
13-
get "/"
14-
ENV['OK'] = 'true'
15-
rescue Errno::ECONNREFUSED => error
16-
if retries < 10
17-
retries += 1
18-
sleep 1
19-
retry
20-
else
21-
raise error
22-
end
23-
end
24-
end
4+
CODE_VERSION = ENV.fetch('PACT_BROKER_CODE_VERSION')
5+
DATABASE_VERSION = ENV.fetch('PACT_BROKER_DATABASE_VERSION')
6+
CONSUMER_VERSION = CODE_VERSION == 'head' ? '100.100.100' : CODE_VERSION
7+
TAG = SecureRandom.hex
8+
9+
describe "Code version #{CODE_VERSION} running against database version #{DATABASE_VERSION}" do
10+
11+
before do
12+
wait_for_server_to_start
13+
end
14+
15+
let(:path) { "/pacts/provider/Bar/consumer/Foo/version/#{CONSUMER_VERSION}" }
16+
let(:response_body_json) { JSON.parse(subject.body) }
17+
let(:pact_content) do
18+
pact = load_json_fixture('foo-bar.json')
19+
pact['interactions'][0]['providerState'] = "the code version is #{CODE_VERSION}"
20+
pact.to_json
21+
end
22+
23+
let(:app) do
24+
Rack::ReverseProxy.new do
25+
reverse_proxy_options preserve_host: true
26+
reverse_proxy '/', "http://localhost:#{ENV.fetch('PORT')}/"
2527
end
28+
end
2629

27-
let(:pact_content) { load_fixture('foo-bar.json') }
28-
let(:path) { "/pacts/provider/Bar/consumer/Foo/version/1.2.3" }
29-
let(:response_body_json) { JSON.parse(subject.body) }
30+
describe "tagging a consumer version" do
31+
let(:path) { "/pacticipants/Foo/versions/#{CONSUMER_VERSION}/tags/#{TAG}"}
32+
subject { put path, nil, {'CONTENT_TYPE' => 'application/json' }; last_response }
3033

31-
let(:app) do
32-
Rack::ReverseProxy.new do
33-
reverse_proxy_options preserve_host: true
34-
reverse_proxy '/', "http://localhost:#{ENV.fetch('PORT')}/"
35-
end
34+
it "returns a success status" do
35+
expect(subject.status.to_s).to match /20\d/
3636
end
37+
end
3738

39+
describe "publishing a pact" do
3840
subject { put path, pact_content, {'CONTENT_TYPE' => 'application/json' }; last_response }
3941

40-
4142
it "returns a success status" do
4243
expect(subject.status.to_s).to match /20\d/
4344
end
45+
end
46+
47+
describe "retrieving a pact" do
48+
subject { get path; last_response }
49+
50+
it "returns the pact in the body" do
51+
expect(response_body_json).to include JSON.parse(pact_content)
52+
end
53+
end
54+
55+
describe "retrieving the latest tagged pact" do
56+
let(:path) { "/pacts/provider/Bar/consumer/Foo/latest" }
57+
subject { get path; last_response }
58+
59+
it "returns the latest pact" do
60+
expect(subject.headers['X-Pact-Consumer-Version']).to eq '100.100.100'
61+
end
62+
end
63+
64+
describe "retrieving the latest tagged pact" do
65+
let(:path) { "/pacts/provider/Bar/consumer/Foo/latest/#{TAG}" }
66+
subject { get path; last_response }
4467

4568
it "returns the pact in the body" do
4669
expect(response_body_json).to include JSON.parse(pact_content)
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
require 'support/fixture_helpers'
2+
require 'support/request_helpers'
23
require 'rack/test'
34

45
RSpec.configure do | config |
56

67
config.include Rack::Test::Methods
8+
config.include RequestHelpers
9+
config.include FixtureHelpers
710

811
config.mock_with :rspec do |mocks|
912
mocks.verify_partial_doubles = true
1013
end
1114

12-
config.include FixtureHelpers
15+
config.after(:suite) do
16+
puts "***************************************************************************"
17+
puts "Pact Broker logs are in db/test/backwards_compatibility/log/pact_broker.log"
18+
puts "***************************************************************************"
19+
end
1320
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module RequestHelpers
2+
3+
def wait_for_server_to_start
4+
unless ENV['OK']
5+
retries = 0
6+
begin
7+
get "/"
8+
ENV['OK'] = 'true'
9+
rescue Errno::ECONNREFUSED => error
10+
if retries < 10
11+
retries += 1
12+
sleep 1
13+
retry
14+
else
15+
raise error
16+
end
17+
end
18+
end
19+
end
20+
end

tasks/db.rake

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ namespace :bundler do
88
end
99

1010
namespace :db do
11+
12+
task :spec do
13+
Bundler.with_clean_env do
14+
# todo check for ruby version
15+
system('cd db/test/backwards_compatibility && bundle exec rake db:check_backwards_compatibility')
16+
success = $?.exitstatus == 0
17+
exit(1) unless success
18+
end
19+
end
20+
1121
task :env => ['bundler:setup'] do
1222
# Require RACK_ENV to be set for tasks that will be called in production
1323
raise "Please specify RACK_ENV" unless ENV['RACK_ENV']

0 commit comments

Comments
 (0)