pact_broker 1.10.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/pact_broker/api/resources/pact.rb +4 -1
- data/lib/pact_broker/pacts/merger.rb +15 -10
- data/lib/pact_broker/version.rb +1 -1
- data/spec/features/merge_pact_spec.rb +9 -1
- data/spec/fixtures/a_consumer-a_provider-3.json +22 -0
- data/spec/fixtures/a_consumer-a_provider-conflict.json +22 -0
- data/spec/fixtures/a_consumer-a_provider-merged.json +3 -3
- data/spec/fixtures/consumer-provider.json +4 -1
- data/spec/lib/pact_broker/pacts/merger_spec.rb +96 -67
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f09781dc3499bf4830479db69b58d8d26436bea
|
4
|
+
data.tar.gz: 74c433ce40b144bd5e2c1cef5efa4a3d892a94f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85c3c79444957b05bcfd754e5d12b69a2d8196439a45e1f6ce1edaf2d2936e850f9656bbb3396d243434bd80a11a659a257b2614b10385c52e5a07b7b14fcfa1
|
7
|
+
data.tar.gz: 78782d8518d1bf357c9d434b5ed40d77d6ab83f6f73745e063f22a2f5c747e61f65201af92851206c4b70cdab532d6d51a5d05a8d72cfbd25dfec0834723d80c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@ 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
|
+
|
6
|
+
#### 1.11.0 (2016-08-13)
|
7
|
+
* 18ffc4a - Add conflict guards to pact merger (Steve Pletcher, Fri Aug 5 12:31:30 2016 -0400)
|
8
|
+
|
5
9
|
#### 1.10.0 (2016-08-01)
|
6
10
|
* efdde13 - Add ability to merge pacts via PATCH requests (Steve Pletcher, Thu Jul 28 16:29:22 2016 -0400)
|
7
11
|
|
@@ -40,7 +40,10 @@ module PactBroker
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def is_conflict?
|
43
|
-
|
43
|
+
merge_conflict = request.patch? && resource_exists? &&
|
44
|
+
Pacts::Merger.conflict?(pact.json_content, pact_params.json_content)
|
45
|
+
|
46
|
+
potential_duplicate_pacticipants?(pact_params.pacticipant_names) || merge_conflict
|
44
47
|
end
|
45
48
|
|
46
49
|
def malformed_request?
|
@@ -6,6 +6,17 @@ module PactBroker
|
|
6
6
|
|
7
7
|
extend self
|
8
8
|
|
9
|
+
def conflict? original_json, additional_json
|
10
|
+
original, additional = [original_json, additional_json].map{|str| JSON.parse(str, PACT_PARSING_OPTIONS) }
|
11
|
+
|
12
|
+
additional["interactions"].any? do |new_interaction|
|
13
|
+
original["interactions"].any? do |original_interaction|
|
14
|
+
same_description_and_state?(original_interaction, new_interaction) &&
|
15
|
+
!same_request_properties?(original_interaction["request"], new_interaction["request"])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
9
20
|
# Accepts two hashes representing pacts, outputs a merged hash
|
10
21
|
# Does not make any guarantees about order of interactions
|
11
22
|
def merge_pacts original_json, additional_json
|
@@ -16,7 +27,7 @@ module PactBroker
|
|
16
27
|
additional["interactions"].each do |new_interaction|
|
17
28
|
# check to see if this interaction matches an existing interaction
|
18
29
|
overwrite_index = original["interactions"].find_index do |original_interaction|
|
19
|
-
|
30
|
+
same_description_and_state?(original_interaction, new_interaction)
|
20
31
|
end
|
21
32
|
|
22
33
|
# overwrite existing interaction if a match is found, otherwise appends the new interaction
|
@@ -32,21 +43,15 @@ module PactBroker
|
|
32
43
|
|
33
44
|
private
|
34
45
|
|
35
|
-
def matching_request? original_interaction, new_interaction
|
36
|
-
same_description_and_state?(original_interaction, new_interaction) &&
|
37
|
-
same_request_properties?(original_interaction["request"], new_interaction["request"])
|
38
|
-
end
|
39
|
-
|
40
46
|
def same_description_and_state? original, additional
|
41
47
|
original["description"] == additional["description"] &&
|
42
48
|
original["provider_state"] == additional["provider_state"]
|
43
49
|
end
|
44
50
|
|
45
51
|
def same_request_properties? original, additional
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
method_matches && path_matches && original["headers"] == additional["headers"]
|
52
|
+
attributes_match = %w(method path query body headers).all? do |attribute|
|
53
|
+
original[attribute] == additional[attribute]
|
54
|
+
end
|
50
55
|
end
|
51
56
|
end
|
52
57
|
end
|
data/lib/pact_broker/version.rb
CHANGED
@@ -25,7 +25,7 @@ describe "Merging a pact" do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
context "when a pact for this consumer version does exist" do
|
28
|
-
let(:existing_pact_content) { load_fixture('a_consumer-a_provider-
|
28
|
+
let(:existing_pact_content) { load_fixture('a_consumer-a_provider-3.json') }
|
29
29
|
let(:merged_pact_content) { load_fixture('a_consumer-a_provider-merged.json') }
|
30
30
|
|
31
31
|
before do
|
@@ -43,6 +43,14 @@ describe "Merging a pact" do
|
|
43
43
|
it "returns the merged pact in the response body" do
|
44
44
|
expect(response_body_json).to contain_hash JSON.parse(merged_pact_content)
|
45
45
|
end
|
46
|
+
|
47
|
+
context "with a conflicting request" do
|
48
|
+
let(:existing_pact_content) { load_fixture('a_consumer-a_provider-conflict.json') }
|
49
|
+
|
50
|
+
it "returns a 409 Conflict" do
|
51
|
+
expect(subject.status).to be 409
|
52
|
+
end
|
53
|
+
end
|
46
54
|
end
|
47
55
|
|
48
56
|
context "when the pacticipant names in the path do not match those in the pact" do
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "A Consumer"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "A Provider"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description" : "another request for something",
|
11
|
+
"provider_state": null,
|
12
|
+
"request": {
|
13
|
+
"method": "get",
|
14
|
+
"path" : "/something_else"
|
15
|
+
},
|
16
|
+
"response": {
|
17
|
+
"status": 200,
|
18
|
+
"body" : "something"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "A Consumer"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "A Provider"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description" : "a request for something",
|
11
|
+
"provider_state": null,
|
12
|
+
"request": {
|
13
|
+
"method": "post",
|
14
|
+
"path" : "/something"
|
15
|
+
},
|
16
|
+
"response": {
|
17
|
+
"status": 200,
|
18
|
+
"body" : "something"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -10,7 +10,7 @@
|
|
10
10
|
"description" : "a request for something",
|
11
11
|
"provider_state": null,
|
12
12
|
"request": {
|
13
|
-
"method": "
|
13
|
+
"method": "get",
|
14
14
|
"path" : "/something"
|
15
15
|
},
|
16
16
|
"response": {
|
@@ -19,11 +19,11 @@
|
|
19
19
|
}
|
20
20
|
},
|
21
21
|
{
|
22
|
-
"description" : "
|
22
|
+
"description" : "another request for something",
|
23
23
|
"provider_state": null,
|
24
24
|
"request": {
|
25
25
|
"method": "get",
|
26
|
-
"path" : "/
|
26
|
+
"path" : "/something_else"
|
27
27
|
},
|
28
28
|
"response": {
|
29
29
|
"status": 200,
|
@@ -28,86 +28,115 @@ module PactBroker
|
|
28
28
|
}
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
@pact_to_merge = load_json_fixture('consumer-provider.json')
|
33
|
-
end
|
34
|
-
|
35
|
-
it "merges two pacts" do
|
36
|
-
@pact_to_merge["interactions"] << example_interaction
|
37
|
-
result = merge_pacts(example_pact, @pact_to_merge)
|
38
|
-
expect(result["interactions"]).to match_array(example_pact["interactions"].push(example_interaction))
|
39
|
-
end
|
40
|
-
|
41
|
-
it "is idempotent" do
|
42
|
-
@pact_to_merge["interactions"] << example_interaction
|
43
|
-
first_result = merge_pacts(example_pact, @pact_to_merge)
|
44
|
-
second_result = merge_pacts(first_result, @pact_to_merge)
|
45
|
-
expect(first_result).to contain_hash second_result
|
46
|
-
end
|
47
|
-
|
48
|
-
it "overwrites identical interactions" do
|
49
|
-
@pact_to_merge["interactions"][0]["response"]["body"] = "changed!"
|
50
|
-
result = merge_pacts(example_pact, @pact_to_merge)
|
51
|
-
|
52
|
-
expect(result["interactions"].length).to eq example_pact["interactions"].length
|
53
|
-
expect(result["interactions"].first["response"]["body"]).to eq "changed!"
|
54
|
-
end
|
55
|
-
|
56
|
-
it "appends interactions with a different provider state" do
|
57
|
-
@pact_to_merge["interactions"][0]["provider_state"] = "upside down"
|
31
|
+
describe "#merge" do
|
58
32
|
|
59
|
-
|
60
|
-
|
61
|
-
|
33
|
+
before :each do
|
34
|
+
@pact_to_merge = load_json_fixture('consumer-provider.json')
|
35
|
+
end
|
62
36
|
|
63
|
-
|
64
|
-
|
37
|
+
it "merges two pacts" do
|
38
|
+
@pact_to_merge["interactions"] << example_interaction
|
39
|
+
result = merge_pacts(example_pact, @pact_to_merge)
|
40
|
+
expect(result["interactions"]).to match_array(example_pact["interactions"].push(example_interaction))
|
41
|
+
end
|
65
42
|
|
66
|
-
|
67
|
-
|
68
|
-
|
43
|
+
it "is idempotent" do
|
44
|
+
@pact_to_merge["interactions"] << example_interaction
|
45
|
+
first_result = merge_pacts(example_pact, @pact_to_merge)
|
46
|
+
second_result = merge_pacts(first_result, @pact_to_merge)
|
47
|
+
expect(first_result).to contain_hash second_result
|
48
|
+
end
|
69
49
|
|
70
|
-
|
71
|
-
|
50
|
+
it "overwrites identical interactions" do
|
51
|
+
@pact_to_merge["interactions"][0]["response"]["body"] = "changed!"
|
52
|
+
result = merge_pacts(example_pact, @pact_to_merge)
|
72
53
|
|
73
|
-
|
74
|
-
|
75
|
-
|
54
|
+
expect(result["interactions"].length).to eq example_pact["interactions"].length
|
55
|
+
expect(result["interactions"].first["response"]["body"]).to eq "changed!"
|
56
|
+
end
|
76
57
|
|
77
|
-
|
78
|
-
|
58
|
+
it "appends interactions with a different provider state" do
|
59
|
+
@pact_to_merge["interactions"][0]["provider_state"] = "upside down"
|
79
60
|
|
80
|
-
|
81
|
-
|
82
|
-
|
61
|
+
result = merge_pacts(example_pact, @pact_to_merge)
|
62
|
+
expect(result["interactions"].length).to eq example_pact["interactions"].length + 1
|
63
|
+
end
|
83
64
|
|
84
|
-
|
85
|
-
|
65
|
+
it "appends interactions with a different description" do
|
66
|
+
@pact_to_merge["interactions"][0]["description"] = "getting $$$"
|
86
67
|
|
87
|
-
|
88
|
-
|
89
|
-
|
68
|
+
result = merge_pacts(example_pact, @pact_to_merge)
|
69
|
+
expect(result["interactions"].length).to eq example_pact["interactions"].length + 1
|
70
|
+
end
|
90
71
|
|
91
|
-
|
92
|
-
|
93
|
-
|
72
|
+
# helper that lets these specs deal with hashes instead of JSON strings
|
73
|
+
def merge_pacts(a, b, return_hash = true)
|
74
|
+
result = PactBroker::Pacts::Merger.merge_pacts(a.to_json, b.to_json)
|
94
75
|
|
95
|
-
|
96
|
-
|
76
|
+
return_hash ? JSON.parse(result) : result
|
77
|
+
end
|
97
78
|
end
|
98
79
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
80
|
+
describe "#conflict?" do
|
81
|
+
before :each do
|
82
|
+
@pact_to_compare = load_json_fixture('consumer-provider.json')
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns false if interactions have different descriptions" do
|
86
|
+
@pact_to_compare["interactions"][0]["description"] = "something else"
|
87
|
+
|
88
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq false
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns false if interactions have different provider states" do
|
92
|
+
@pact_to_compare["interactions"][0]["provider_state"] = "some other thing"
|
93
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq false
|
94
|
+
end
|
95
|
+
|
96
|
+
context "when interactions have the same desc/state" do
|
97
|
+
it "returns false if request parameters are the same" do
|
98
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq false
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns true if requests have a different query" do
|
102
|
+
@pact_to_compare["interactions"][0]["request"]["query"] = "foo=bar&baz=qux"
|
103
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
104
|
+
end
|
105
|
+
|
106
|
+
it "returns true if requests have a different body" do
|
107
|
+
@pact_to_compare["interactions"][0]["request"]["body"] = { "something" => { "nested" => "deeply" } }
|
108
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
109
|
+
end
|
110
|
+
|
111
|
+
it "returns true if request method is different" do
|
112
|
+
@pact_to_compare["interactions"][0]["request"]["method"] = "post"
|
113
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns true if request path is different" do
|
117
|
+
@pact_to_compare["interactions"][0]["request"]["path"] = "/new_path"
|
118
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns true if request headers are different" do
|
122
|
+
@pact_to_compare["interactions"][0]["request"]["headers"]["Content-Type"] = "text/html"
|
123
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
124
|
+
end
|
125
|
+
|
126
|
+
it "returns true if request has additional headers" do
|
127
|
+
@pact_to_compare["interactions"][0]["request"]["headers"]["Accept"] = "text/html"
|
128
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
129
|
+
end
|
130
|
+
|
131
|
+
it "returns true if request has missing headers" do
|
132
|
+
@pact_to_compare["interactions"][0]["request"]["headers"].delete("Content-Type")
|
133
|
+
expect(compare_pacts(example_pact, @pact_to_compare)).to eq true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def compare_pacts(a, b)
|
138
|
+
PactBroker::Pacts::Merger.conflict?(a.to_json, b.to_json)
|
139
|
+
end
|
111
140
|
end
|
112
141
|
end
|
113
142
|
end
|
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: 1.
|
4
|
+
version: 1.11.0
|
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: 2016-08-
|
13
|
+
date: 2016-08-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
@@ -581,6 +581,8 @@ files:
|
|
581
581
|
- spec/features/publish_pact_spec.rb
|
582
582
|
- spec/features/update_pacticipant_spec.rb
|
583
583
|
- spec/fixtures/a_consumer-a_provider-2.json
|
584
|
+
- spec/fixtures/a_consumer-a_provider-3.json
|
585
|
+
- spec/fixtures/a_consumer-a_provider-conflict.json
|
584
586
|
- spec/fixtures/a_consumer-a_provider-merged.json
|
585
587
|
- spec/fixtures/a_consumer-a_provider.json
|
586
588
|
- spec/fixtures/consumer-provider.json
|
@@ -738,6 +740,8 @@ test_files:
|
|
738
740
|
- spec/features/publish_pact_spec.rb
|
739
741
|
- spec/features/update_pacticipant_spec.rb
|
740
742
|
- spec/fixtures/a_consumer-a_provider-2.json
|
743
|
+
- spec/fixtures/a_consumer-a_provider-3.json
|
744
|
+
- spec/fixtures/a_consumer-a_provider-conflict.json
|
741
745
|
- spec/fixtures/a_consumer-a_provider-merged.json
|
742
746
|
- spec/fixtures/a_consumer-a_provider.json
|
743
747
|
- spec/fixtures/consumer-provider.json
|