pact 0.1.28 → 1.3.3
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.
- data/.gitignore +2 -1
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +374 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +58 -55
- data/README.md +214 -139
- data/Rakefile +4 -28
- data/bin/pact +2 -2
- data/config.ru +3 -0
- data/documentation/README.md +13 -0
- data/documentation/configuration.md +166 -0
- data/documentation/diff_formatter_embedded.png +0 -0
- data/documentation/diff_formatter_list.png +0 -0
- data/documentation/diff_formatter_unix.png +0 -0
- data/example/animal-service/Gemfile +14 -0
- data/example/animal-service/Gemfile.lock +69 -0
- data/example/animal-service/Rakefile +5 -0
- data/example/animal-service/config.ru +3 -0
- data/example/animal-service/db/animal_db.sqlite3 +0 -0
- data/example/animal-service/lib/animal_service/animal_repository.rb +12 -0
- data/example/animal-service/lib/animal_service/api.rb +28 -0
- data/example/animal-service/lib/animal_service/db.rb +5 -0
- data/example/animal-service/spec/service_consumers/pact_helper.rb +11 -0
- data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +26 -0
- data/example/zoo-app/Gemfile +12 -0
- data/example/zoo-app/Gemfile.lock +63 -0
- data/example/zoo-app/Rakefile +5 -0
- data/example/zoo-app/doc/pacts/markdown/README.md +3 -0
- data/example/zoo-app/doc/pacts/markdown/Zoo App - Animal Service.md +75 -0
- data/example/zoo-app/lib/zoo_app/animal_service_client.rb +40 -0
- data/example/zoo-app/lib/zoo_app/models/alligator.rb +15 -0
- data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +67 -0
- data/example/zoo-app/spec/service_providers/animal_service_client_spec.rb +71 -0
- data/example/zoo-app/spec/service_providers/pact_helper.rb +15 -0
- data/example/zoo-app/spec/spec_helper.rb +6 -0
- data/lib/pact/cli.rb +138 -0
- data/lib/pact/configuration.rb +169 -28
- data/lib/pact/consumer/app_manager.rb +10 -29
- data/lib/pact/consumer/configuration/configuration_extensions.rb +15 -0
- data/lib/pact/consumer/configuration/dsl.rb +12 -0
- data/lib/pact/consumer/configuration/mock_service.rb +91 -0
- data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
- data/lib/pact/consumer/configuration/service_provider.rb +40 -0
- data/lib/pact/consumer/configuration.rb +11 -0
- data/lib/pact/consumer/consumer_contract_builder.rb +44 -47
- data/lib/pact/consumer/interaction_builder.rb +41 -0
- data/lib/pact/consumer/interactions_filter.rb +48 -0
- data/lib/pact/consumer/mock_service/app.rb +82 -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 +1 -339
- 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/rspec.rb +9 -19
- data/lib/pact/consumer/server.rb +90 -0
- data/lib/pact/consumer/spec_hooks.rb +38 -0
- data/lib/pact/consumer/world.rb +37 -0
- data/lib/pact/consumer.rb +10 -7
- data/lib/pact/consumer_contract/consumer_contract.rb +115 -0
- data/lib/pact/consumer_contract/consumer_contract_writer.rb +84 -0
- data/lib/pact/consumer_contract/file_name.rb +19 -0
- data/lib/pact/consumer_contract/headers.rb +51 -0
- data/lib/pact/consumer_contract/interaction.rb +67 -0
- data/lib/pact/consumer_contract/pact_file.rb +24 -0
- data/lib/pact/consumer_contract/request.rb +73 -0
- data/lib/pact/consumer_contract/service_consumer.rb +28 -0
- data/lib/pact/consumer_contract/service_provider.rb +28 -0
- data/lib/pact/consumer_contract.rb +1 -110
- data/lib/pact/doc/doc_file.rb +40 -0
- data/lib/pact/doc/generate.rb +11 -0
- data/lib/pact/doc/generator.rb +82 -0
- data/lib/pact/doc/interaction_view_model.rb +114 -0
- data/lib/pact/doc/markdown/consumer_contract_renderer.rb +56 -0
- data/lib/pact/doc/markdown/generator.rb +26 -0
- data/lib/pact/doc/markdown/index_renderer.rb +41 -0
- data/lib/pact/doc/markdown/interaction.erb +14 -0
- data/lib/pact/doc/markdown/interaction_renderer.rb +38 -0
- data/lib/pact/doc/sort_interactions.rb +17 -0
- data/lib/pact/matchers/actual_type.rb +16 -0
- data/lib/pact/matchers/base_difference.rb +37 -0
- data/lib/pact/matchers/differ.rb +153 -0
- data/lib/pact/matchers/difference.rb +13 -0
- data/lib/pact/matchers/difference_indicator.rb +26 -0
- data/lib/pact/matchers/embedded_diff_formatter.rb +62 -0
- data/lib/pact/matchers/expected_type.rb +35 -0
- data/lib/pact/matchers/index_not_found.rb +15 -0
- data/lib/pact/matchers/list_diff_formatter.rb +101 -0
- data/lib/pact/matchers/matchers.rb +91 -37
- data/lib/pact/matchers/no_diff_indicator.rb +18 -0
- data/lib/pact/matchers/regexp_difference.rb +13 -0
- data/lib/pact/matchers/type_difference.rb +16 -0
- data/lib/pact/matchers/unexpected_index.rb +11 -0
- data/lib/pact/matchers/unexpected_key.rb +11 -0
- data/lib/pact/matchers/unix_diff_formatter.rb +114 -0
- data/lib/pact/project_root.rb +7 -0
- data/lib/pact/provider/configuration/configuration_extension.rb +58 -0
- data/lib/pact/provider/configuration/dsl.rb +13 -0
- data/lib/pact/provider/configuration/pact_verification.rb +46 -0
- data/lib/pact/provider/configuration/service_provider_config.rb +16 -0
- data/lib/pact/provider/configuration/service_provider_dsl.rb +59 -0
- data/lib/pact/provider/configuration.rb +7 -0
- data/lib/pact/provider/context.rb +0 -0
- data/lib/pact/provider/matchers/messages.rb +45 -0
- data/lib/pact/provider/pact_helper_locator.rb +22 -0
- data/lib/pact/provider/pact_spec_runner.rb +123 -0
- data/lib/pact/provider/pact_verification.rb +17 -0
- data/lib/pact/provider/print_missing_provider_states.rb +30 -0
- data/lib/pact/provider/request.rb +70 -0
- data/lib/pact/provider/rspec/backtrace_formatter.rb +43 -0
- data/lib/pact/provider/rspec/custom_options_file +0 -0
- data/lib/pact/provider/rspec/formatter_rspec_2.rb +65 -0
- data/lib/pact/provider/rspec/formatter_rspec_3.rb +96 -0
- data/lib/pact/provider/rspec/matchers.rb +97 -0
- data/lib/pact/provider/rspec.rb +181 -0
- data/lib/pact/provider/state/provider_state.rb +181 -0
- data/lib/pact/provider/state/provider_state_configured_modules.rb +13 -0
- data/lib/pact/provider/state/provider_state_manager.rb +42 -0
- data/lib/pact/provider/state/provider_state_proxy.rb +39 -0
- data/lib/pact/provider/test_methods.rb +47 -0
- data/lib/pact/provider/verification_report.rb +36 -0
- data/lib/pact/provider/world.rb +23 -0
- data/lib/pact/provider.rb +3 -0
- data/lib/pact/reification.rb +6 -4
- data/lib/pact/rspec.rb +53 -0
- data/lib/pact/shared/active_support_support.rb +51 -0
- data/lib/pact/shared/dsl.rb +76 -0
- data/lib/pact/shared/jruby_support.rb +18 -0
- data/lib/pact/shared/json_differ.rb +15 -0
- data/lib/pact/shared/key_not_found.rb +15 -0
- data/lib/pact/shared/null_expectation.rb +31 -0
- data/lib/pact/shared/request.rb +80 -0
- data/lib/pact/shared/text_differ.rb +14 -0
- data/lib/pact/something_like.rb +49 -0
- data/lib/pact/symbolize_keys.rb +12 -0
- data/lib/pact/tasks/task_helper.rb +36 -0
- data/lib/pact/tasks/verification_task.rb +87 -0
- data/lib/pact/tasks.rb +2 -0
- data/lib/pact/templates/provider_state.erb +14 -0
- data/lib/pact/term.rb +47 -2
- data/lib/pact/version.rb +1 -1
- data/lib/pact.rb +1 -1
- data/lib/tasks/pact.rake +25 -2
- data/pact.gemspec +13 -11
- data/{scratchpad.txt → scratchpad.rb} +18 -2
- data/spec/features/consumption_spec.rb +24 -56
- data/spec/features/production_spec.rb +19 -24
- data/spec/features/{producer_states → provider_states}/zebras.rb +3 -3
- data/spec/integration/consumer_spec.rb +212 -0
- data/spec/integration/pact/consumer_configuration_spec.rb +66 -0
- data/spec/integration/pact/provider_configuration_spec.rb +25 -0
- data/spec/lib/pact/cli_spec.rb +47 -0
- data/spec/lib/pact/configuration_spec.rb +269 -7
- data/spec/lib/pact/consumer/app_manager_spec.rb +3 -3
- data/spec/lib/pact/consumer/configuration_spec.rb +57 -0
- data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +52 -70
- data/spec/lib/pact/consumer/interaction_builder_spec.rb +91 -0
- data/spec/lib/pact/consumer/interactions_spec.rb +64 -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/request_spec.rb +24 -0
- data/spec/lib/pact/consumer/service_consumer_spec.rb +1 -1
- data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +58 -0
- data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +180 -0
- data/spec/lib/pact/consumer_contract/consumer_contract_writer_spec.rb +111 -0
- data/spec/lib/pact/consumer_contract/headers_spec.rb +107 -0
- data/spec/lib/pact/consumer_contract/interaction_spec.rb +107 -0
- data/spec/lib/pact/{request_spec.rb → consumer_contract/request_spec.rb} +80 -67
- data/spec/lib/pact/doc/generator_spec.rb +84 -0
- data/spec/lib/pact/doc/interaction_view_model_spec.rb +132 -0
- data/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb +29 -0
- data/spec/lib/pact/doc/markdown/index_renderer_spec.rb +29 -0
- data/spec/lib/pact/matchers/differ_spec.rb +214 -0
- data/spec/lib/pact/matchers/difference_spec.rb +22 -0
- data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +90 -0
- data/spec/lib/pact/matchers/index_not_found_spec.rb +21 -0
- data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +114 -0
- data/spec/lib/pact/matchers/matchers_spec.rb +400 -254
- data/spec/lib/pact/matchers/regexp_difference_spec.rb +20 -0
- data/spec/lib/pact/matchers/type_difference_spec.rb +34 -0
- data/spec/lib/pact/matchers/unexpected_index_spec.rb +20 -0
- data/spec/lib/pact/matchers/unexpected_key_spec.rb +20 -0
- data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +216 -0
- data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +30 -0
- data/spec/lib/pact/provider/configuration/pact_verification_spec.rb +43 -0
- data/spec/lib/pact/provider/configuration/service_provider_config_spec.rb +21 -0
- data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +108 -0
- data/spec/lib/pact/provider/configuration_spec.rb +50 -0
- data/spec/lib/pact/provider/matchers/messages_spec.rb +116 -0
- data/spec/lib/pact/provider/pact_helper_locator_spec.rb +54 -0
- data/spec/lib/pact/provider/print_missing_provider_states_spec.rb +19 -0
- data/spec/lib/pact/provider/request_spec.rb +78 -0
- data/spec/lib/pact/provider/rspec/formatter_rspec_2_spec.rb +68 -0
- data/spec/lib/pact/provider/rspec/formatter_rspec_3_spec.rb +72 -0
- data/spec/lib/pact/provider/rspec_spec.rb +55 -0
- data/spec/lib/pact/provider/state/provider_state_manager_spec.rb +89 -0
- data/spec/lib/pact/provider/state/provider_state_proxy_spec.rb +80 -0
- data/spec/lib/pact/provider/state/provider_state_spec.rb +213 -0
- data/spec/lib/pact/provider/world_spec.rb +41 -0
- data/spec/lib/pact/reification_spec.rb +24 -0
- data/spec/lib/pact/shared/dsl_spec.rb +86 -0
- data/spec/lib/pact/shared/json_differ_spec.rb +36 -0
- data/spec/lib/pact/shared/key_not_found_spec.rb +20 -0
- data/spec/lib/pact/shared/request_spec.rb +111 -0
- data/spec/lib/pact/shared/text_differ_spec.rb +54 -0
- data/spec/lib/pact/something_like_spec.rb +21 -0
- data/spec/lib/pact/tasks/task_helper_spec.rb +74 -0
- data/spec/lib/pact/tasks/verification_task_spec.rb +75 -0
- data/spec/lib/pact/term_spec.rb +57 -4
- data/spec/pact_specification/compliance-1.0.0.rb +47 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/standalone/consumer_fail_test.rb +55 -0
- data/spec/standalone/consumer_pass_test.rb +51 -0
- data/spec/support/a_consumer-a_producer.json +2 -4
- 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/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 +41 -2
- data/spec/support/test_app_pass.json +19 -2
- data/spec/support/test_app_with_right_content_type_differ.json +23 -0
- data/tasks/pact-test.rake +98 -8
- data/tasks/spec.rake +8 -0
- metadata +393 -95
- data/lib/pact/app.rb +0 -32
- data/lib/pact/consumer/configuration_dsl.rb +0 -71
- data/lib/pact/consumer/dsl.rb +0 -98
- data/lib/pact/consumer/interaction.rb +0 -70
- data/lib/pact/consumer/run_condor.rb +0 -4
- data/lib/pact/consumer/run_mock_contract_service.rb +0 -13
- data/lib/pact/consumer/service_consumer.rb +0 -22
- data/lib/pact/consumer/service_producer.rb +0 -23
- data/lib/pact/json_warning.rb +0 -23
- data/lib/pact/producer/configuration_dsl.rb +0 -62
- data/lib/pact/producer/matchers.rb +0 -22
- data/lib/pact/producer/pact_spec_runner.rb +0 -57
- data/lib/pact/producer/producer_state.rb +0 -81
- data/lib/pact/producer/rspec.rb +0 -127
- data/lib/pact/producer/test_methods.rb +0 -89
- data/lib/pact/producer.rb +0 -1
- data/lib/pact/rake_task.rb +0 -64
- data/lib/pact/request.rb +0 -109
- data/lib/pact/verification_task.rb +0 -57
- data/spec/integration/pact/configuration_spec.rb +0 -65
- data/spec/lib/pact/consumer/dsl_spec.rb +0 -52
- data/spec/lib/pact/consumer/interaction_spec.rb +0 -108
- data/spec/lib/pact/consumer/mock_service_spec.rb +0 -147
- data/spec/lib/pact/consumer_contract_spec.rb +0 -125
- data/spec/lib/pact/producer/configuration_dsl_spec.rb +0 -101
- data/spec/lib/pact/producer/producer_state_spec.rb +0 -103
- data/spec/lib/pact/producer/rspec_spec.rb +0 -48
- data/spec/lib/pact/verification_task_spec.rb +0 -64
- data/spec/support/pact_rake_support.rb +0 -41
|
@@ -1,340 +1,2 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require 'uri'
|
|
3
|
-
require 'json'
|
|
4
|
-
require 'hashie'
|
|
5
|
-
require 'singleton'
|
|
6
|
-
require 'logger'
|
|
7
|
-
require 'awesome_print'
|
|
8
|
-
require 'awesome_print/core_ext/logger' #For some reason we get an error indicating that the method 'ap' is private unless we load this specifically
|
|
9
|
-
require 'json/add/regexp'
|
|
10
|
-
require 'pact/matchers'
|
|
1
|
+
require 'pact/consumer/mock_service/app'
|
|
11
2
|
|
|
12
|
-
AwesomePrint.defaults = {
|
|
13
|
-
indent: -2,
|
|
14
|
-
plain: true,
|
|
15
|
-
index: false
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module Pact
|
|
19
|
-
module Consumer
|
|
20
|
-
|
|
21
|
-
class InteractionList
|
|
22
|
-
include Singleton
|
|
23
|
-
|
|
24
|
-
attr_reader :interactions
|
|
25
|
-
attr_reader :unexpected_requests
|
|
26
|
-
|
|
27
|
-
def initialize
|
|
28
|
-
clear
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# For testing, sigh
|
|
32
|
-
def clear
|
|
33
|
-
@interactions = []
|
|
34
|
-
@matched_interactions = []
|
|
35
|
-
@unexpected_requests = []
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def add interactions
|
|
39
|
-
@interactions << interactions
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def register_matched interaction
|
|
43
|
-
@matched_interactions << interaction
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def register_unexpected request
|
|
47
|
-
@unexpected_requests << request
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def all_matched?
|
|
51
|
-
interaction_diffs.empty?
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def missing_interactions
|
|
55
|
-
@interactions - @matched_interactions
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def interaction_diffs
|
|
59
|
-
{
|
|
60
|
-
:missing_interactions => missing_interactions,
|
|
61
|
-
:unexpected_requests => unexpected_requests
|
|
62
|
-
}.inject({}) do | hash, pair |
|
|
63
|
-
hash[pair.first] = pair.last if pair.last.any?
|
|
64
|
-
hash
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
module RackHelper
|
|
71
|
-
def params_hash env
|
|
72
|
-
env["QUERY_STRING"].split("&").collect{| param| param.split("=")}.inject({}){|params, param| params[param.first] = URI.decode(param.last); params }
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
class StartupPoll
|
|
77
|
-
|
|
78
|
-
def initialize name, logger
|
|
79
|
-
@name = name
|
|
80
|
-
@logger = logger
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def match? env
|
|
84
|
-
env['REQUEST_PATH'] == '/index.html' &&
|
|
85
|
-
env['REQUEST_METHOD'] == 'GET'
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def respond env
|
|
89
|
-
@logger.info "#{@name} started up"
|
|
90
|
-
[200, {}, ['Started up fine']]
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
class CapybaraIdentify
|
|
95
|
-
|
|
96
|
-
def initialize name, logger
|
|
97
|
-
@name = name
|
|
98
|
-
@logger = logger
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def match? env
|
|
102
|
-
env["PATH_INFO"] == "/__identify__"
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def respond env
|
|
106
|
-
[200, {}, [object_id.to_s]]
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
class InteractionDelete
|
|
111
|
-
|
|
112
|
-
include RackHelper
|
|
113
|
-
|
|
114
|
-
def initialize name, logger
|
|
115
|
-
@name = name
|
|
116
|
-
@logger = logger
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def match? env
|
|
120
|
-
env['REQUEST_PATH'].start_with?('/interactions') &&
|
|
121
|
-
env['REQUEST_METHOD'] == 'DELETE'
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def respond env
|
|
125
|
-
InteractionList.instance.clear
|
|
126
|
-
@logger.info "Cleared interactions before example \"#{params_hash(env)['example_description']}\""
|
|
127
|
-
[200, {}, ['Deleted interactions']]
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
class InteractionPost
|
|
132
|
-
|
|
133
|
-
def initialize name, logger
|
|
134
|
-
@name = name
|
|
135
|
-
@logger = logger
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def match? env
|
|
139
|
-
env['REQUEST_PATH'] == '/interactions' &&
|
|
140
|
-
env['REQUEST_METHOD'] == 'POST'
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def respond env
|
|
144
|
-
interactions = Hashie::Mash.new(JSON.load(env['rack.input'].string))
|
|
145
|
-
InteractionList.instance.add interactions
|
|
146
|
-
@logger.info "Added interaction to #{@name}"
|
|
147
|
-
@logger.ap interactions
|
|
148
|
-
[200, {}, ['Added interactions']]
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
module RequestExtractor
|
|
153
|
-
|
|
154
|
-
REQUEST_KEYS = Hashie::Mash.new({
|
|
155
|
-
'REQUEST_METHOD' => :method,
|
|
156
|
-
'REQUEST_PATH' => :path,
|
|
157
|
-
'QUERY_STRING' => :query,
|
|
158
|
-
'rack.input' => :body
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
def request_from env
|
|
162
|
-
request = env.inject({}) do |memo, (k, v)|
|
|
163
|
-
request_key = REQUEST_KEYS[k]
|
|
164
|
-
memo[request_key] = v if request_key
|
|
165
|
-
memo
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
mashed_request = Hashie::Mash.new request
|
|
169
|
-
mashed_request[:headers] = headers_from env
|
|
170
|
-
body_string = mashed_request[:body].read
|
|
171
|
-
|
|
172
|
-
if body_string.empty?
|
|
173
|
-
mashed_request.delete :body
|
|
174
|
-
else
|
|
175
|
-
body_is_json = mashed_request[:headers]['Content-Type'] =~ /json/
|
|
176
|
-
mashed_request[:body] = body_is_json ? JSON.parse(body_string) : body_string
|
|
177
|
-
end
|
|
178
|
-
mashed_request[:method] = mashed_request[:method].downcase
|
|
179
|
-
mashed_request
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def headers_from env
|
|
183
|
-
headers = env.reject{ |key, value| !(key.start_with?("HTTP") || key == 'CONTENT_TYPE')}
|
|
184
|
-
headers.inject({}) do | hash, header |
|
|
185
|
-
hash[standardise_header(header.first)] = header.last
|
|
186
|
-
hash
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
def standardise_header header
|
|
191
|
-
header.gsub(/^HTTP_/, '').split("_").collect{|word| word[0] + word[1..-1].downcase}.join("-")
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
class InteractionReplay
|
|
196
|
-
include Pact::Matchers
|
|
197
|
-
include RequestExtractor
|
|
198
|
-
|
|
199
|
-
def initialize name, logger
|
|
200
|
-
@name = name
|
|
201
|
-
@logger = logger
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def match? env
|
|
205
|
-
true # default handler
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def respond env
|
|
209
|
-
find_response request_from(env)
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
private
|
|
213
|
-
|
|
214
|
-
def find_response raw_request
|
|
215
|
-
actual_request = Request::Actual.from_hash(raw_request)
|
|
216
|
-
@logger.info "#{@name} received request"
|
|
217
|
-
@logger.ap actual_request.as_json
|
|
218
|
-
candidates = []
|
|
219
|
-
matching_interactions = InteractionList.instance.interactions.select do |interaction|
|
|
220
|
-
expected_request = Request::Expected.from_hash(interaction.request.merge(:description => interaction.description))
|
|
221
|
-
candidates << expected_request if expected_request.matches_route? actual_request
|
|
222
|
-
expected_request.match actual_request
|
|
223
|
-
end
|
|
224
|
-
if matching_interactions.size > 1
|
|
225
|
-
@logger.info "Multiple interactions found on #{@name}:"
|
|
226
|
-
@logger.ap matching_interactions
|
|
227
|
-
raise 'Multiple interactions found!'
|
|
228
|
-
end
|
|
229
|
-
if matching_interactions.empty?
|
|
230
|
-
handle_unrecognised_request(actual_request, candidates)
|
|
231
|
-
else
|
|
232
|
-
response = response_from(matching_interactions.first.response)
|
|
233
|
-
InteractionList.instance.register_matched matching_interactions.first
|
|
234
|
-
@logger.info "Found matching response on #{@name}:"
|
|
235
|
-
@logger.ap response
|
|
236
|
-
response
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def handle_unrecognised_request request, candidates
|
|
241
|
-
@logger.ap "No interaction found on #{@name} for request \"#{candidates.map(&:description).join(', ')}\""
|
|
242
|
-
@logger.ap 'Interaction diffs for that route:'
|
|
243
|
-
interaction_diff = candidates.map do |candidate|
|
|
244
|
-
diff(candidate.as_json, request.as_json)
|
|
245
|
-
end.to_a
|
|
246
|
-
@logger.ap(interaction_diff)
|
|
247
|
-
response = {message: "No interaction found for #{request.path}", interaction_diff: interaction_diff}
|
|
248
|
-
[500, {'Content-Type' => 'application/json'}, [response.to_json]]
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
def response_from response
|
|
252
|
-
[response.status, (response.headers || {}).to_hash, [render_body(response.body)]]
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def render_body body
|
|
256
|
-
return '' unless body
|
|
257
|
-
body.kind_of?(String) ? body.force_encoding('utf-8') : body.to_json
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def logger_info_ap msg
|
|
261
|
-
@logger.info msg
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
class VerificationGet
|
|
266
|
-
|
|
267
|
-
include RackHelper
|
|
268
|
-
|
|
269
|
-
def initialize name, logger, log_description
|
|
270
|
-
@name = name
|
|
271
|
-
@logger = logger
|
|
272
|
-
@log_description = log_description
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def match? env
|
|
276
|
-
env['REQUEST_PATH'].start_with?('/verify') &&
|
|
277
|
-
env['REQUEST_METHOD'] == 'GET'
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def respond env
|
|
281
|
-
if InteractionList.instance.all_matched?
|
|
282
|
-
@logger.info "Veryifying - interactions matched for example \"#{example_description(env)}\""
|
|
283
|
-
[200, {}, ['Interactions matched']]
|
|
284
|
-
else
|
|
285
|
-
@logger.warn "Verifying - actual interactions do not match expected interactions for example \"#{example_description(env)}\". Missing interactions:"
|
|
286
|
-
@logger.ap InteractionList.instance.interaction_diffs, :warn
|
|
287
|
-
[500, {}, ["Actual interactions do not match expected interactions for mock #{@name}. See #{@log_description} for details."]]
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def example_description env
|
|
292
|
-
params_hash(env)['example_description']
|
|
293
|
-
end
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
class MockService
|
|
297
|
-
|
|
298
|
-
def initialize options = {}
|
|
299
|
-
options = {log_file: STDOUT}.merge options
|
|
300
|
-
log_stream = options[:log_file]
|
|
301
|
-
@logger = Logger.new log_stream
|
|
302
|
-
|
|
303
|
-
log_description = if log_stream.is_a? File
|
|
304
|
-
File.absolute_path(log_stream).gsub(Dir.pwd + "/", '')
|
|
305
|
-
else
|
|
306
|
-
"standard out/err"
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
@name = options.fetch(:name, "MockService")
|
|
310
|
-
@handlers = [
|
|
311
|
-
StartupPoll.new(@name, @logger),
|
|
312
|
-
CapybaraIdentify.new(@name, @logger),
|
|
313
|
-
VerificationGet.new(@name, @logger, log_description),
|
|
314
|
-
InteractionPost.new(@name, @logger),
|
|
315
|
-
InteractionDelete.new(@name, @logger),
|
|
316
|
-
InteractionReplay.new(@name, @logger)
|
|
317
|
-
]
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
def to_s
|
|
321
|
-
"#{@name} #{super.to_s}"
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
def call env
|
|
325
|
-
response = []
|
|
326
|
-
begin
|
|
327
|
-
relevant_handler = @handlers.detect { |handler| handler.match? env }
|
|
328
|
-
response = relevant_handler.respond env
|
|
329
|
-
rescue Exception => e
|
|
330
|
-
@logger.ap 'Error ocurred in mock service:'
|
|
331
|
-
@logger.ap e
|
|
332
|
-
@logger.ap e.backtrace
|
|
333
|
-
raise e
|
|
334
|
-
end
|
|
335
|
-
response
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'pact/consumer/mock_service_interaction_expectation'
|
|
3
|
+
|
|
4
|
+
module Pact
|
|
5
|
+
module Consumer
|
|
6
|
+
class MockServiceClient
|
|
7
|
+
|
|
8
|
+
MOCK_SERVICE_ADMINISTRATON_HEADERS = {'X-Pact-Mock-Service' => 'true'}
|
|
9
|
+
|
|
10
|
+
def initialize port
|
|
11
|
+
@http = Net::HTTP.new('localhost', port)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def verify example_description
|
|
15
|
+
response = http.request_get("/interactions/verification?example_description=#{URI.encode(example_description)}", MOCK_SERVICE_ADMINISTRATON_HEADERS)
|
|
16
|
+
raise "\e[31m#{response.body}\e[m" unless response.is_a? Net::HTTPSuccess
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def log msg
|
|
20
|
+
http.request_get("/log?msg=#{URI.encode(msg)}", MOCK_SERVICE_ADMINISTRATON_HEADERS)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def wait_for_interactions wait_max_seconds, poll_interval
|
|
24
|
+
wait_until_true(wait_max_seconds, poll_interval) do
|
|
25
|
+
response = http.request_get("/interactions/missing", MOCK_SERVICE_ADMINISTRATON_HEADERS)
|
|
26
|
+
JSON.parse(response.body)['size'] == 0
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def clear_interactions example_description
|
|
31
|
+
http.delete("/interactions?example_description=#{URI.encode(example_description)}", MOCK_SERVICE_ADMINISTRATON_HEADERS)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def add_expected_interaction interaction
|
|
35
|
+
response = http.request_post('/interactions', MockServiceInteractionExpectation.new(interaction).to_json, MOCK_SERVICE_ADMINISTRATON_HEADERS.merge("Content-Type" => "application/json"))
|
|
36
|
+
raise "\e[31m#{response.body}\e[m" unless response.is_a? Net::HTTPSuccess
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.clear_interactions port, example_description
|
|
40
|
+
Net::HTTP.new("localhost", port).delete("/interactions?example_description=#{URI.encode(example_description)}", MOCK_SERVICE_ADMINISTRATON_HEADERS)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def write_pact pacticipant_details
|
|
44
|
+
response = http.request_post("/pact", pacticipant_details.to_json, MOCK_SERVICE_ADMINISTRATON_HEADERS.merge("Content-Type" => "application/json"))
|
|
45
|
+
raise "\e[31m#{response.body}\e[m" unless response.is_a? Net::HTTPSuccess
|
|
46
|
+
response.body
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
attr_reader :http
|
|
52
|
+
|
|
53
|
+
#todo: in need a better home (where can we move it?)
|
|
54
|
+
def wait_until_true timeout=3, interval=0.1
|
|
55
|
+
time_limit = Time.now + timeout
|
|
56
|
+
loop do
|
|
57
|
+
result = yield
|
|
58
|
+
return if result || Time.now >= time_limit
|
|
59
|
+
sleep interval
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'pact/reification'
|
|
2
|
+
|
|
3
|
+
# Represents the Interaction in the form required by the MockService
|
|
4
|
+
# The json generated will be posted to the MockService to register the expectation
|
|
5
|
+
module Pact
|
|
6
|
+
module Consumer
|
|
7
|
+
class MockServiceInteractionExpectation
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def initialize interaction
|
|
11
|
+
@interaction = interaction
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_hash
|
|
15
|
+
hash = {:description => interaction.description}
|
|
16
|
+
hash[:provider_state] = interaction.provider_state if interaction.provider_state
|
|
17
|
+
options = interaction.request.options.empty? ? {} : { options: interaction.request.options}
|
|
18
|
+
hash[:request] = interaction.request.as_json.merge(options)
|
|
19
|
+
hash[:response] = interaction.response
|
|
20
|
+
hash
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def as_json options = {}
|
|
24
|
+
to_hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_json opts = {}
|
|
28
|
+
as_json.to_json(opts)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
attr_reader :interaction
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'pact/shared/request'
|
|
2
|
+
require 'pact/shared/key_not_found'
|
|
3
|
+
|
|
4
|
+
module Pact
|
|
5
|
+
module Consumer
|
|
6
|
+
module Request
|
|
7
|
+
class Actual < Pact::Request::Base
|
|
8
|
+
|
|
9
|
+
def self.from_hash(hash)
|
|
10
|
+
sym_hash = symbolize_keys hash
|
|
11
|
+
method = sym_hash.fetch(:method)
|
|
12
|
+
path = sym_hash.fetch(:path)
|
|
13
|
+
query = sym_hash.fetch(:query)
|
|
14
|
+
headers = sym_hash.fetch(:headers)
|
|
15
|
+
body = sym_hash.fetch(:body, nil)
|
|
16
|
+
new(method, path, headers, body, query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def self.key_not_found
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/pact/consumer/rspec.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
require_relative 'configuration_dsl'
|
|
1
|
+
require 'pact/consumer'
|
|
2
|
+
require 'pact/consumer/spec_hooks'
|
|
3
|
+
require 'pact/rspec'
|
|
5
4
|
|
|
6
5
|
module Pact
|
|
7
6
|
module Consumer
|
|
@@ -11,33 +10,24 @@ module Pact
|
|
|
11
10
|
end
|
|
12
11
|
end
|
|
13
12
|
|
|
13
|
+
hooks = Pact::Consumer::SpecHooks.new
|
|
14
|
+
|
|
14
15
|
RSpec.configure do |config|
|
|
15
16
|
config.include Pact::Consumer::RSpec, :pact => true
|
|
16
17
|
|
|
17
18
|
config.before :all, :pact => true do
|
|
18
|
-
|
|
19
|
-
FileUtils.mkdir_p Pact.configuration.pact_dir
|
|
19
|
+
hooks.before_all
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
config.before :each, :pact => true do | example |
|
|
23
|
-
|
|
24
|
-
Pact.configuration.logger.info "Clearing all expectations"
|
|
25
|
-
Pact::Consumer::AppManager.instance.ports_of_mock_services.each do | port |
|
|
26
|
-
Net::HTTP.new("localhost", port).delete("/interactions?example_description=#{URI.encode(example_description)}")
|
|
27
|
-
end
|
|
23
|
+
hooks.before_each Pact::RSpec.full_description(example)
|
|
28
24
|
end
|
|
29
25
|
|
|
30
26
|
config.after :each, :pact => true do | example |
|
|
31
|
-
|
|
32
|
-
Pact.configuration.logger.info "Verifying interactions for #{example_description}"
|
|
33
|
-
Pact.configuration.producer_verifications.each do | producer_verification |
|
|
34
|
-
producer_verification.call example_description
|
|
35
|
-
end
|
|
27
|
+
hooks.after_each Pact::RSpec.full_description(example)
|
|
36
28
|
end
|
|
37
29
|
|
|
38
30
|
config.after :suite do
|
|
39
|
-
|
|
40
|
-
Pact::Consumer::AppManager.instance.kill_all
|
|
41
|
-
Pact::Consumer::AppManager.instance.clear_all
|
|
31
|
+
hooks.after_suite
|
|
42
32
|
end
|
|
43
33
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'rack'
|
|
4
|
+
|
|
5
|
+
# Copied shamelessly from Capybara
|
|
6
|
+
module Pact
|
|
7
|
+
class Server
|
|
8
|
+
class Middleware
|
|
9
|
+
attr_accessor :error
|
|
10
|
+
|
|
11
|
+
def initialize(app)
|
|
12
|
+
@app = app
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call(env)
|
|
16
|
+
if env["PATH_INFO"] == "/__identify__"
|
|
17
|
+
[200, {}, [@app.object_id.to_s]]
|
|
18
|
+
else
|
|
19
|
+
begin
|
|
20
|
+
@app.call(env)
|
|
21
|
+
rescue StandardError => e
|
|
22
|
+
@error = e unless @error
|
|
23
|
+
raise e
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
def ports
|
|
31
|
+
@ports ||= {}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :app, :port
|
|
36
|
+
|
|
37
|
+
def initialize(app, port)
|
|
38
|
+
@app = app
|
|
39
|
+
@middleware = Middleware.new(@app)
|
|
40
|
+
@server_thread = nil # supress warnings
|
|
41
|
+
@port = port
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset_error!
|
|
45
|
+
@middleware.error = nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def error
|
|
49
|
+
@middleware.error
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def host
|
|
53
|
+
"localhost"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def responsive?
|
|
57
|
+
return false if @server_thread && @server_thread.join(0)
|
|
58
|
+
|
|
59
|
+
res = Net::HTTP.start(host, @port) { |http| http.get('/__identify__') }
|
|
60
|
+
|
|
61
|
+
if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
|
|
62
|
+
return res.body == @app.object_id.to_s
|
|
63
|
+
end
|
|
64
|
+
rescue SystemCallError
|
|
65
|
+
return false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def run_default_server(app, port)
|
|
69
|
+
require 'rack/handler/webrick'
|
|
70
|
+
Rack::Handler::WEBrick.run(app, :Port => port, :AccessLog => [], :Logger => WEBrick::Log::new(nil, 0))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def boot
|
|
74
|
+
unless responsive?
|
|
75
|
+
Pact::Server.ports[@app.object_id] = @port
|
|
76
|
+
|
|
77
|
+
@server_thread = Thread.new do
|
|
78
|
+
run_default_server(@middleware, @port)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
Timeout.timeout(60) { @server_thread.join(0.1) until responsive? }
|
|
82
|
+
end
|
|
83
|
+
rescue Timeout::Error
|
|
84
|
+
raise "Rack application timed out during boot"
|
|
85
|
+
else
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'pact/doc/generate'
|
|
2
|
+
require 'pact/consumer/world'
|
|
3
|
+
|
|
4
|
+
module Pact
|
|
5
|
+
module Consumer
|
|
6
|
+
class SpecHooks
|
|
7
|
+
|
|
8
|
+
def before_all
|
|
9
|
+
Pact::Consumer::AppManager.instance.spawn_all
|
|
10
|
+
FileUtils.mkdir_p Pact.configuration.pact_dir
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def before_each example_description
|
|
14
|
+
Pact.consumer_world.register_pact_example_ran
|
|
15
|
+
Pact.configuration.logger.info "Clearing all expectations"
|
|
16
|
+
Pact::Consumer::AppManager.instance.ports_of_mock_services.each do | port |
|
|
17
|
+
Pact::Consumer::MockServiceClient.clear_interactions port, example_description
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def after_each example_description
|
|
22
|
+
Pact.configuration.logger.info "Verifying interactions for #{example_description}"
|
|
23
|
+
Pact.configuration.provider_verifications.each do | provider_verification |
|
|
24
|
+
provider_verification.call example_description
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def after_suite
|
|
29
|
+
if Pact.consumer_world.any_pact_examples_ran?
|
|
30
|
+
Pact.consumer_world.consumer_contract_builders.each { | c | c.write_pact }
|
|
31
|
+
Pact::Doc::Generate.call
|
|
32
|
+
Pact::Consumer::AppManager.instance.kill_all
|
|
33
|
+
Pact::Consumer::AppManager.instance.clear_all
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Pact
|
|
2
|
+
|
|
3
|
+
def self.consumer_world
|
|
4
|
+
@consumer_world ||= Pact::Consumer::World.new
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# internal api, for testing only
|
|
8
|
+
def self.clear_consumer_world
|
|
9
|
+
@consumer_world = nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Consumer
|
|
13
|
+
class World
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@any_pact_examples_ran = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def consumer_contract_builders
|
|
20
|
+
@consumer_contract_builders ||= []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def add_consumer_contract_builder consumer_contract_builder
|
|
24
|
+
consumer_contract_builders << consumer_contract_builder
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def register_pact_example_ran
|
|
28
|
+
@any_pact_examples_ran = true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def any_pact_examples_ran?
|
|
32
|
+
@any_pact_examples_ran
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|