pact-mock_service 0.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.
- checksums.yaml +15 -0
- data/.gitignore +29 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +100 -0
- data/LICENSE.txt +22 -0
- data/README.md +314 -0
- data/Rakefile +6 -0
- data/bin/pact-mock-service +3 -0
- data/lib/pact/consumer/app_manager.rb +159 -0
- data/lib/pact/consumer/interactions_filter.rb +48 -0
- data/lib/pact/consumer/mock_service/app.rb +84 -0
- data/lib/pact/consumer/mock_service/interaction_delete.rb +33 -0
- data/lib/pact/consumer/mock_service/interaction_list.rb +76 -0
- data/lib/pact/consumer/mock_service/interaction_mismatch.rb +73 -0
- data/lib/pact/consumer/mock_service/interaction_post.rb +31 -0
- data/lib/pact/consumer/mock_service/interaction_replay.rb +139 -0
- data/lib/pact/consumer/mock_service/log_get.rb +28 -0
- data/lib/pact/consumer/mock_service/missing_interactions_get.rb +30 -0
- data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +31 -0
- data/lib/pact/consumer/mock_service/pact_post.rb +33 -0
- data/lib/pact/consumer/mock_service/rack_request_helper.rb +51 -0
- data/lib/pact/consumer/mock_service/verification_get.rb +68 -0
- data/lib/pact/consumer/mock_service.rb +2 -0
- data/lib/pact/consumer/mock_service_client.rb +65 -0
- data/lib/pact/consumer/mock_service_interaction_expectation.rb +37 -0
- data/lib/pact/consumer/request.rb +27 -0
- data/lib/pact/consumer/server.rb +90 -0
- data/lib/pact/consumer_contract/consumer_contract_writer.rb +84 -0
- data/lib/pact/mock_service/cli.rb +49 -0
- data/lib/pact/mock_service/version.rb +5 -0
- data/lib/pact/mock_service.rb +1 -0
- data/pact-mock-service.gemspec +41 -0
- data/spec/lib/pact/consumer/app_manager_spec.rb +42 -0
- data/spec/lib/pact/consumer/mock_service/app_spec.rb +52 -0
- data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +78 -0
- data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +70 -0
- data/spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb +12 -0
- data/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb +88 -0
- data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +142 -0
- data/spec/lib/pact/consumer/mock_service_client_spec.rb +88 -0
- data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +54 -0
- data/spec/lib/pact/consumer/service_consumer_spec.rb +11 -0
- data/spec/lib/pact/consumer_contract/consumer_contract_writer_spec.rb +111 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/a_consumer-a_producer.json +32 -0
- data/spec/support/a_consumer-a_provider.json +32 -0
- data/spec/support/active_support_if_configured.rb +6 -0
- data/spec/support/app_for_config_ru.rb +4 -0
- data/spec/support/case-insensitive-response-header-matching.json +21 -0
- data/spec/support/case-insensitive-response-header-matching.rb +15 -0
- data/spec/support/consumer_contract_template.json +24 -0
- data/spec/support/dsl_spec_support.rb +7 -0
- data/spec/support/factories.rb +82 -0
- data/spec/support/generated_index.md +4 -0
- data/spec/support/generated_markdown.md +55 -0
- data/spec/support/interaction_view_model.json +63 -0
- data/spec/support/interaction_view_model_with_terms.json +50 -0
- data/spec/support/markdown_pact.json +48 -0
- data/spec/support/missing_provider_states_output.txt +25 -0
- data/spec/support/options.json +21 -0
- data/spec/support/options_app.rb +15 -0
- data/spec/support/pact_helper.rb +57 -0
- data/spec/support/shared_examples_for_request.rb +94 -0
- data/spec/support/spec_support.rb +20 -0
- data/spec/support/stubbing.json +22 -0
- data/spec/support/stubbing_using_allow.rb +29 -0
- data/spec/support/term.json +48 -0
- data/spec/support/test_app_fail.json +61 -0
- data/spec/support/test_app_pass.json +38 -0
- data/spec/support/test_app_with_right_content_type_differ.json +23 -0
- data/tasks/spec.rake +6 -0
- metadata +388 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "an easy consumer"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "a provider which returns headers that don't match the expected case"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "a test request",
|
11
|
+
"request": {
|
12
|
+
"method": "get",
|
13
|
+
"path": "/"
|
14
|
+
},
|
15
|
+
"response": {
|
16
|
+
"status": 200,
|
17
|
+
"headers": {"Content-Type": "application/hippo"}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pact
|
2
|
+
module Test
|
3
|
+
class CaseInsensitiveResponseHeadersApp
|
4
|
+
|
5
|
+
def call env
|
6
|
+
[200, {'cOnTent-tYpe' => 'application/hippo'},[]]
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Pact.service_provider "Provider" do
|
14
|
+
app { Pact::Test::CaseInsensitiveResponseHeadersApp.new }
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"provider": {
|
3
|
+
"name": "a provider"
|
4
|
+
},
|
5
|
+
"consumer": {
|
6
|
+
"name": "a consumer"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "request one",
|
11
|
+
"request": {
|
12
|
+
"method": "get",
|
13
|
+
"path": "/path_one"
|
14
|
+
},
|
15
|
+
"response": {
|
16
|
+
"status" : 200
|
17
|
+
},
|
18
|
+
"provider_state": "state one"
|
19
|
+
}
|
20
|
+
],
|
21
|
+
"metadata": {
|
22
|
+
"pactSpecificationVersion": "1.0"
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
require 'hashie/extensions/key_conversion'
|
3
|
+
|
4
|
+
module Pact
|
5
|
+
module HashUtils
|
6
|
+
|
7
|
+
class Converter < Hash
|
8
|
+
include Hashie::Extensions::KeyConversion
|
9
|
+
include Hashie::Extensions::DeepMerge
|
10
|
+
end
|
11
|
+
|
12
|
+
def symbolize_keys hash
|
13
|
+
Hash[Converter[hash].symbolize_keys]
|
14
|
+
end
|
15
|
+
|
16
|
+
def stringify_keys hash
|
17
|
+
Hash[Converter[hash].stringify_keys]
|
18
|
+
end
|
19
|
+
|
20
|
+
def deep_merge hash1, hash2
|
21
|
+
Converter[hash1].deep_merge(Converter[hash2])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class InteractionFactory
|
27
|
+
|
28
|
+
extend Pact::HashUtils
|
29
|
+
|
30
|
+
def self.create hash = {}
|
31
|
+
defaults = {
|
32
|
+
'description' => 'a description',
|
33
|
+
'provider_state' => 'a thing exists',
|
34
|
+
'request' => {
|
35
|
+
'path' => '/path',
|
36
|
+
'method' => 'get',
|
37
|
+
},
|
38
|
+
'response' => {
|
39
|
+
'status' => 200,
|
40
|
+
'body' => {a: 'response body'}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
Pact::Interaction.from_hash(stringify_keys(deep_merge(defaults, stringify_keys(hash))))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
class ConsumerContractFactory
|
49
|
+
extend Pact::HashUtils
|
50
|
+
DEFAULTS = {:consumer_name => 'consumer',
|
51
|
+
:provider_name => 'provider',
|
52
|
+
:interactions => [InteractionFactory.create]}
|
53
|
+
|
54
|
+
def self.create overrides = {}
|
55
|
+
options = deep_merge(symbolize_keys(DEFAULTS), symbolize_keys(overrides))
|
56
|
+
Pact::ConsumerContract.new({:consumer => Pact::ServiceConsumer.new(name: options[:consumer_name]),
|
57
|
+
:provider => Pact::ServiceProvider.new(name: options[:provider_name]),
|
58
|
+
:interactions => options[:interactions]})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
class ResponseFactory
|
65
|
+
extend Pact::HashUtils
|
66
|
+
DEFAULTS = {:status => 200, :body => {a: 'body'}}.freeze
|
67
|
+
def self.create_hash overrides = {}
|
68
|
+
deep_merge(DEFAULTS, overrides)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class RequestFactory
|
73
|
+
extend Pact::HashUtils
|
74
|
+
DEFAULTS = {:path => '/path', :method => 'get', :query => 'query', :headers => {}}.freeze
|
75
|
+
def self.create_hash overrides = {}
|
76
|
+
deep_merge(DEFAULTS, overrides)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.create_actual overrides = {}
|
80
|
+
Pact::Consumer::Request::Actual.from_hash(create_hash(overrides))
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
### A pact between Some Consumer and Some Provider
|
2
|
+
|
3
|
+
#### Requests from Some Consumer to Some Provider
|
4
|
+
|
5
|
+
* [A request for alligators](#a_request_for_alligators_given_alligators_exist) given alligators exist
|
6
|
+
|
7
|
+
* [A request for polar bears](#a_request_for_polar_bears)
|
8
|
+
|
9
|
+
#### Interactions
|
10
|
+
|
11
|
+
<a name="a_request_for_alligators_given_alligators_exist"></a>
|
12
|
+
Given **alligators exist**, upon receiving **a request for alligators** from Some Consumer, with
|
13
|
+
```json
|
14
|
+
{
|
15
|
+
"method": "get",
|
16
|
+
"path": "/alligators"
|
17
|
+
}
|
18
|
+
```
|
19
|
+
Some Provider will respond with:
|
20
|
+
```json
|
21
|
+
{
|
22
|
+
"status": 200,
|
23
|
+
"headers": {
|
24
|
+
"Content-Type": "application/json"
|
25
|
+
},
|
26
|
+
"body": {
|
27
|
+
"alligators": [
|
28
|
+
{
|
29
|
+
"name": "Bob",
|
30
|
+
"phoneNumber": "12345678"
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
34
|
+
}
|
35
|
+
```
|
36
|
+
<a name="a_request_for_polar_bears"></a>
|
37
|
+
Upon receiving **a request for polar bears** from Some Consumer, with
|
38
|
+
```json
|
39
|
+
{
|
40
|
+
"method": "get",
|
41
|
+
"path": "/polar-bears"
|
42
|
+
}
|
43
|
+
```
|
44
|
+
Some Provider will respond with:
|
45
|
+
```json
|
46
|
+
{
|
47
|
+
"status": 404,
|
48
|
+
"headers": {
|
49
|
+
"Content-Type": "application/json"
|
50
|
+
},
|
51
|
+
"body": {
|
52
|
+
"message": "Sorry, due to climate change, the polar bears are currently unavailable."
|
53
|
+
}
|
54
|
+
}
|
55
|
+
```
|
@@ -0,0 +1,63 @@
|
|
1
|
+
{
|
2
|
+
"provider": {
|
3
|
+
"name": "a provider"
|
4
|
+
},
|
5
|
+
"consumer": {
|
6
|
+
"name": "a consumer"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "a request with a body and headers",
|
11
|
+
"request": {
|
12
|
+
"method": "get",
|
13
|
+
"path": "/path",
|
14
|
+
"query": "some=thing",
|
15
|
+
"headers": {
|
16
|
+
"key": "a header"
|
17
|
+
},
|
18
|
+
"body": {
|
19
|
+
"key": "a body"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
"response": {}
|
23
|
+
},
|
24
|
+
{
|
25
|
+
"description": "a request with an empty body and empty headers",
|
26
|
+
"request": {
|
27
|
+
"method": "get",
|
28
|
+
"path": "/",
|
29
|
+
"headers": {},
|
30
|
+
"body": {}
|
31
|
+
},
|
32
|
+
"response": {}
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"description": "a response with a body and headers",
|
36
|
+
"request": {
|
37
|
+
"method": "get",
|
38
|
+
"path": "/"
|
39
|
+
},
|
40
|
+
"response": {
|
41
|
+
"headers": {
|
42
|
+
"key": "a header"
|
43
|
+
},
|
44
|
+
"body": {
|
45
|
+
"key": "a body"
|
46
|
+
},
|
47
|
+
"status": 200
|
48
|
+
}
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"description": "a response with an empty body and empty headers",
|
52
|
+
"request": {
|
53
|
+
"method": "get",
|
54
|
+
"path": "/"
|
55
|
+
},
|
56
|
+
"response": {
|
57
|
+
"status": 200,
|
58
|
+
"headers": {},
|
59
|
+
"body": {}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
]
|
63
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
{
|
2
|
+
"provider": {
|
3
|
+
"name": "a provider"
|
4
|
+
},
|
5
|
+
"consumer": {
|
6
|
+
"name": "a consumer"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "an interaction with terms",
|
11
|
+
"request": {
|
12
|
+
"method": "post",
|
13
|
+
"path": "/path",
|
14
|
+
"query": "some=thing",
|
15
|
+
"headers": {
|
16
|
+
"key": "a header"
|
17
|
+
},
|
18
|
+
"body": {
|
19
|
+
"term": {
|
20
|
+
"json_class": "Pact::Term",
|
21
|
+
"data": {
|
22
|
+
"generate": "sunny",
|
23
|
+
"matcher": {
|
24
|
+
"json_class": "Regexp",
|
25
|
+
"o": 0,
|
26
|
+
"s": "sun"
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
},
|
32
|
+
"response": {
|
33
|
+
"status": 200,
|
34
|
+
"body": {
|
35
|
+
"term": {
|
36
|
+
"json_class": "Pact::Term",
|
37
|
+
"data": {
|
38
|
+
"generate": "rainy",
|
39
|
+
"matcher": {
|
40
|
+
"json_class": "Regexp",
|
41
|
+
"o": 0,
|
42
|
+
"s": "rain"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
]
|
50
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
{
|
2
|
+
"provider": {
|
3
|
+
"name": "Some Provider"
|
4
|
+
},
|
5
|
+
"consumer": {
|
6
|
+
"name": "Some Consumer"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "a request for alligators",
|
11
|
+
"provider_state": "alligators exist",
|
12
|
+
"request": {
|
13
|
+
"method": "get",
|
14
|
+
"path": "/alligators"
|
15
|
+
},
|
16
|
+
"response": {
|
17
|
+
"headers" : {"Content-Type": "application/json"},
|
18
|
+
"status" : 200,
|
19
|
+
"body" : {
|
20
|
+
"alligators": [{
|
21
|
+
"name": "Bob",
|
22
|
+
"phoneNumber" : {
|
23
|
+
"json_class": "Pact::Term",
|
24
|
+
"data": {
|
25
|
+
"generate": "12345678",
|
26
|
+
"matcher": {"json_class":"Regexp","o":0,"s":"\\d+"}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}]
|
30
|
+
}
|
31
|
+
}
|
32
|
+
},{
|
33
|
+
"description": "a request for polar bears",
|
34
|
+
"provider_state": null,
|
35
|
+
"request": {
|
36
|
+
"method": "get",
|
37
|
+
"path": "/polar-bears"
|
38
|
+
},
|
39
|
+
"response": {
|
40
|
+
"headers" : {"Content-Type": "application/json"},
|
41
|
+
"status" : 404,
|
42
|
+
"body" : {
|
43
|
+
"message": "Sorry, due to climate change, the polar bears are currently unavailable."
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
]
|
48
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Pact.provider_states_for "Consumer 1" do
|
2
|
+
|
3
|
+
provider_state "state1" do
|
4
|
+
set_up do
|
5
|
+
# Your set up code goes here
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
provider_state "state2" do
|
10
|
+
set_up do
|
11
|
+
# Your set up code goes here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
Pact.provider_states_for "Consumer 2" do
|
18
|
+
|
19
|
+
provider_state "state3" do
|
20
|
+
set_up do
|
21
|
+
# Your set up code goes here
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "Consumer"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "Provider"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "an OPTIONS request",
|
11
|
+
"request": {
|
12
|
+
"method": "options",
|
13
|
+
"path": "/"
|
14
|
+
},
|
15
|
+
"response": {
|
16
|
+
"status": 200
|
17
|
+
},
|
18
|
+
"provider_state": null
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'pact/provider/rspec'
|
2
|
+
|
3
|
+
class App
|
4
|
+
def self.call env
|
5
|
+
if env['REQUEST_METHOD'] == 'OPTIONS'
|
6
|
+
[200, {}, []]
|
7
|
+
else
|
8
|
+
[500, {}, ["Expected an options request"]]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Pact.service_provider 'Provider' do
|
14
|
+
app { App }
|
15
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# This is the pact_helper for rake pact:tests
|
2
|
+
require 'json'
|
3
|
+
require 'pact/provider/rspec'
|
4
|
+
require './spec/support/active_support_if_configured'
|
5
|
+
|
6
|
+
module Pact
|
7
|
+
module Test
|
8
|
+
class TestApp
|
9
|
+
def call env
|
10
|
+
if env['PATH_INFO'] == '/weather'
|
11
|
+
[200, {'Content-Type' => 'application/json'}, [{message: WEATHER[:current_state], :array => [{"foo"=> "blah"}]}.to_json]]
|
12
|
+
elsif env['PATH_INFO'] == '/sometext'
|
13
|
+
[200, {'Content-Type' => 'text/plain'}, ['some text']]
|
14
|
+
elsif env['PATH_INFO'] == '/content_type_is_important'
|
15
|
+
[200, {'Content-Type' => 'application/json'}, [{message: "A message", note: "This will cause verify to fail if it using the wrong content type differ."}.to_json]]
|
16
|
+
else
|
17
|
+
raise "unexpected path #{env['PATH_INFO']}!!!"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Pact.configure do | config |
|
23
|
+
config.logger.level = Logger::DEBUG
|
24
|
+
config.diff_formatter = :unix
|
25
|
+
end
|
26
|
+
|
27
|
+
Pact.service_provider "Some Provider" do
|
28
|
+
app { TestApp.new }
|
29
|
+
|
30
|
+
honours_pact_with 'some-test-consumer' do
|
31
|
+
pact_uri './spec/support/test_app_pass.json'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Pact.set_up do
|
36
|
+
WEATHER ||= {}
|
37
|
+
end
|
38
|
+
|
39
|
+
#one with a top level consumer
|
40
|
+
Pact.provider_states_for 'some-test-consumer' do
|
41
|
+
|
42
|
+
provider_state "the weather is sunny" do
|
43
|
+
set_up do
|
44
|
+
|
45
|
+
WEATHER[:current_state] = 'sunny'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#one without a top level consumer
|
51
|
+
Pact.provider_state "the weather is cloudy" do
|
52
|
+
set_up do
|
53
|
+
WEATHER[:current_state] = 'cloudy'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
shared_examples "a request" do
|
2
|
+
|
3
|
+
describe 'matching' do
|
4
|
+
let(:expected) do
|
5
|
+
Pact::Request::Expected.from_hash(
|
6
|
+
{'method' => 'get', 'path' => 'path', 'query' => /b/}
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:actual) do
|
11
|
+
Pact::Consumer::Request::Actual.from_hash({'method' => 'get', 'path' => 'path', 'query' => 'blah', 'headers' => {}, 'body' => ''})
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should match" do
|
15
|
+
expect(expected.difference(actual)).to eq({})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'full_path' do
|
20
|
+
context "with empty path" do
|
21
|
+
subject { described_class.from_hash({:path => '', :method => 'get', :query => '', :headers => {}}) }
|
22
|
+
it "returns the full path"do
|
23
|
+
expect(subject.full_path).to eq "/"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
context "with a path" do
|
27
|
+
subject { described_class.from_hash({:path => '/path', :method => 'get', :query => '', :headers => {}}) }
|
28
|
+
it "returns the full path"do
|
29
|
+
expect(subject.full_path).to eq "/path"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
context "with a path and query" do
|
33
|
+
subject { described_class.from_hash({:path => '/path', :method => 'get', :query => "something", :headers => {}}) }
|
34
|
+
it "returns the full path"do
|
35
|
+
expect(subject.full_path).to eq "/path?something"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
context "with a path and a query that is a Term" do
|
39
|
+
subject { described_class.from_hash({:path => '/path', :method => 'get', :headers => {}, :query => Pact::Term.new(generate: 'a', matcher: /a/)}) }
|
40
|
+
it "returns the full path with reified path" do
|
41
|
+
expect(subject.full_path).to eq "/path?a"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "building from a hash" do
|
47
|
+
|
48
|
+
let(:raw_request) do
|
49
|
+
{
|
50
|
+
'method' => 'get',
|
51
|
+
'path' => '/mallory',
|
52
|
+
'query' => 'query',
|
53
|
+
'headers' => {
|
54
|
+
'Content-Type' => 'application/json'
|
55
|
+
},
|
56
|
+
'body' => 'hello mallory'
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
subject { described_class.from_hash(raw_request) }
|
61
|
+
|
62
|
+
it "extracts the method" do
|
63
|
+
expect(subject.method).to eq 'get'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "extracts the path" do
|
67
|
+
expect(subject.path).to eq '/mallory'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "extracts the body" do
|
71
|
+
expect(subject.body).to eq 'hello mallory'
|
72
|
+
end
|
73
|
+
|
74
|
+
it "extracts the query" do
|
75
|
+
expect(subject.query).to eq 'query'
|
76
|
+
end
|
77
|
+
|
78
|
+
it "blows up if method is absent" do
|
79
|
+
raw_request.delete 'method'
|
80
|
+
expect { described_class.from_hash(raw_request) }.to raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it "blows up if path is absent" do
|
84
|
+
raw_request.delete 'path'
|
85
|
+
expect { described_class.from_hash(raw_request) }.to raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it "does not blow up if body is missing" do
|
89
|
+
raw_request.delete 'body'
|
90
|
+
expect { described_class.from_hash(raw_request) }.to_not raise_error
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'pact/rspec'
|
2
|
+
|
3
|
+
module Pact
|
4
|
+
module SpecSupport
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def remove_ansicolor string
|
9
|
+
string.gsub(/\e\[(\d+)m/, '')
|
10
|
+
end
|
11
|
+
|
12
|
+
Pact::RSpec.with_rspec_2 do
|
13
|
+
|
14
|
+
def instance_double *args
|
15
|
+
double(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "Consumer"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "Provider"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "a test request",
|
11
|
+
"request": {
|
12
|
+
"method": "get",
|
13
|
+
"path": "/"
|
14
|
+
},
|
15
|
+
"response": {
|
16
|
+
"status": 200,
|
17
|
+
"body": "stubbing works"
|
18
|
+
},
|
19
|
+
"provider_state": "something is stubbed"
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'pact/provider/rspec'
|
2
|
+
require 'rspec/mocks'
|
3
|
+
require './spec/support/active_support_if_configured'
|
4
|
+
|
5
|
+
class StubbedThing
|
6
|
+
def self.stub_me
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class App
|
11
|
+
def self.call env
|
12
|
+
[200, {}, [StubbedThing.stub_me]]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Pact.provider_states_for 'Consumer' do
|
17
|
+
provider_state 'something is stubbed' do
|
18
|
+
set_up do
|
19
|
+
allow(StubbedThing).to receive(:stub_me).and_return("stubbing works")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Include the ExampleMethods module after the provider states are declared
|
25
|
+
# to ensure the ordering doesn't matter
|
26
|
+
|
27
|
+
Pact.service_provider 'Provider' do
|
28
|
+
app { App }
|
29
|
+
end
|