pact_broker 1.10.0 → 1.11.0
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.
- 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
|