pact 1.1.0.rc2 → 1.1.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/.gitignore +0 -1
  2. data/CHANGELOG.md +46 -1
  3. data/Gemfile.lock +6 -4
  4. data/README.md +40 -186
  5. data/Rakefile +1 -1
  6. data/documentation/README.md +10 -0
  7. data/documentation/best-practices.md +33 -0
  8. data/documentation/configuration.md +166 -0
  9. data/documentation/diff_formatter_embedded.png +0 -0
  10. data/documentation/diff_formatter_list.png +0 -0
  11. data/documentation/diff_formatter_unix.png +0 -0
  12. data/documentation/faq.md +36 -6
  13. data/documentation/provider-states.md +173 -0
  14. data/documentation/raq.md +4 -4
  15. data/documentation/terminology.md +2 -2
  16. data/example/animal-service/Gemfile.lock +6 -9
  17. data/example/animal-service/Rakefile +2 -0
  18. data/example/animal-service/db/animal_db.sqlite3 +0 -0
  19. data/example/animal-service/lib/animal_service/animal_repository.rb +1 -5
  20. data/example/animal-service/lib/animal_service/api.rb +1 -1
  21. data/example/animal-service/spec/service_consumers/pact_helper.rb +7 -10
  22. data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +5 -1
  23. data/example/zoo-app/Gemfile.lock +6 -9
  24. data/example/zoo-app/Rakefile +5 -0
  25. data/example/zoo-app/doc/markdown/README.md +3 -0
  26. data/example/zoo-app/doc/markdown/Zoo App - Animal Service.md +75 -0
  27. data/example/zoo-app/lib/zoo_app/animal_service_client.rb +2 -2
  28. data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +1 -1
  29. data/example/zoo-app/spec/service_providers/animal_service_client_spec.rb +29 -34
  30. data/example/zoo-app/spec/service_providers/pact_helper.rb +4 -0
  31. data/lib/pact/configuration.rb +49 -1
  32. data/lib/pact/consumer/configuration.rb +4 -172
  33. data/lib/pact/consumer/configuration/configuration_extensions.rb +15 -0
  34. data/lib/pact/consumer/configuration/dsl.rb +12 -0
  35. data/lib/pact/consumer/configuration/mock_service.rb +89 -0
  36. data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
  37. data/lib/pact/consumer/configuration/service_provider.rb +40 -0
  38. data/lib/pact/consumer/mock_service/interaction_mismatch.rb +3 -3
  39. data/lib/pact/consumer/mock_service/interaction_post.rb +2 -2
  40. data/lib/pact/consumer/mock_service/interaction_replay.rb +3 -4
  41. data/lib/pact/consumer/mock_service/verification_get.rb +32 -13
  42. data/lib/pact/consumer/rspec.rb +2 -4
  43. data/lib/pact/consumer/spec_hooks.rb +3 -1
  44. data/lib/pact/consumer_contract/consumer_contract.rb +1 -1
  45. data/lib/pact/consumer_contract/interaction.rb +1 -1
  46. data/lib/pact/doc/doc_file.rb +40 -0
  47. data/lib/pact/doc/generate.rb +11 -0
  48. data/lib/pact/doc/generator.rb +81 -0
  49. data/lib/pact/doc/interaction_view_model.rb +113 -0
  50. data/lib/pact/doc/markdown/generator.rb +26 -0
  51. data/lib/pact/doc/markdown/index_renderer.rb +41 -0
  52. data/lib/pact/doc/markdown/interaction.erb +14 -0
  53. data/lib/pact/doc/markdown/interaction_renderer.rb +38 -0
  54. data/lib/pact/doc/markdown/interactions_renderer.rb +56 -0
  55. data/lib/pact/doc/sort_interactions.rb +17 -0
  56. data/lib/pact/matchers/actual_type.rb +16 -0
  57. data/lib/pact/matchers/base_difference.rb +37 -0
  58. data/lib/pact/matchers/differ.rb +150 -0
  59. data/lib/pact/matchers/difference.rb +5 -30
  60. data/lib/pact/matchers/difference_indicator.rb +26 -0
  61. data/lib/pact/matchers/embedded_diff_formatter.rb +62 -0
  62. data/lib/pact/matchers/expected_type.rb +35 -0
  63. data/lib/pact/matchers/index_not_found.rb +3 -12
  64. data/lib/pact/matchers/{diff_decorator.rb → list_diff_formatter.rb} +28 -11
  65. data/lib/pact/matchers/matchers.rb +35 -39
  66. data/lib/pact/matchers/no_diff_indicator.rb +18 -0
  67. data/lib/pact/matchers/regexp_difference.rb +13 -0
  68. data/lib/pact/matchers/type_difference.rb +16 -0
  69. data/lib/pact/matchers/unexpected_index.rb +3 -13
  70. data/lib/pact/matchers/unexpected_key.rb +3 -12
  71. data/lib/pact/matchers/{plus_minus_diff_decorator.rb → unix_diff_formatter.rb} +22 -7
  72. data/lib/pact/provider/configuration.rb +5 -178
  73. data/lib/pact/provider/configuration/configuration_extension.rb +58 -0
  74. data/lib/pact/provider/configuration/dsl.rb +13 -0
  75. data/lib/pact/provider/configuration/pact_verification.rb +46 -0
  76. data/lib/pact/provider/configuration/service_provider_config.rb +16 -0
  77. data/lib/pact/provider/configuration/service_provider_dsl.rb +54 -0
  78. data/lib/pact/provider/matchers.rb +21 -13
  79. data/lib/pact/provider/matchers/messages.rb +43 -0
  80. data/lib/pact/provider/pact_spec_runner.rb +8 -0
  81. data/lib/pact/provider/rspec.rb +1 -1
  82. data/lib/pact/provider/rspec/formatter.rb +9 -7
  83. data/lib/pact/{consumer_contract → shared}/active_support_support.rb +4 -0
  84. data/lib/pact/shared/jruby_support.rb +18 -0
  85. data/lib/pact/shared/key_not_found.rb +3 -16
  86. data/lib/pact/shared/request.rb +5 -5
  87. data/lib/pact/term.rb +2 -2
  88. data/lib/pact/version.rb +1 -1
  89. data/pact.gemspec +2 -2
  90. data/spec/integration/pact/provider_configuration_spec.rb +2 -1
  91. data/spec/lib/pact/configuration_spec.rb +73 -0
  92. data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +21 -3
  93. data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +134 -0
  94. data/spec/lib/pact/consumer/request_spec.rb +1 -1
  95. data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +1 -1
  96. data/spec/lib/pact/doc/generator_spec.rb +69 -0
  97. data/spec/lib/pact/doc/interaction_view_model_spec.rb +112 -0
  98. data/spec/lib/pact/doc/markdown/index_renderer_spec.rb +29 -0
  99. data/spec/lib/pact/doc/markdown/interactions_renderer_spec.rb +29 -0
  100. data/spec/lib/pact/matchers/differ_spec.rb +214 -0
  101. data/spec/lib/pact/matchers/difference_spec.rb +2 -12
  102. data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +77 -0
  103. data/spec/lib/pact/matchers/index_not_found_spec.rb +21 -0
  104. data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +114 -0
  105. data/spec/lib/pact/matchers/matchers_spec.rb +38 -22
  106. data/spec/lib/pact/matchers/regexp_difference_spec.rb +20 -0
  107. data/spec/lib/pact/matchers/type_difference_spec.rb +34 -0
  108. data/spec/lib/pact/matchers/unexpected_index_spec.rb +20 -0
  109. data/spec/lib/pact/matchers/unexpected_key_spec.rb +20 -0
  110. data/spec/lib/pact/matchers/{plus_minus_diff_decorator_spec.rb → unix_diff_formatter_spec.rb} +35 -6
  111. data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +30 -0
  112. data/spec/lib/pact/provider/configuration/pact_verification_spec.rb +43 -0
  113. data/spec/lib/pact/provider/configuration/service_provider_config_spec.rb +21 -0
  114. data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +92 -0
  115. data/spec/lib/pact/provider/configuration_spec.rb +7 -150
  116. data/spec/lib/pact/provider/matchers/messages_spec.rb +104 -0
  117. data/spec/lib/pact/provider/rspec/formatter_spec.rb +56 -0
  118. data/spec/lib/pact/shared/key_not_found_spec.rb +20 -0
  119. data/spec/lib/pact/shared/request_spec.rb +28 -0
  120. data/spec/spec_helper.rb +3 -0
  121. data/spec/standalone/consumer_fail_test.rb +54 -0
  122. data/spec/standalone/consumer_pass_test.rb +50 -0
  123. data/spec/support/generated_index.md +4 -0
  124. data/spec/support/generated_markdown.md +55 -0
  125. data/spec/support/interaction_view_model.json +63 -0
  126. data/spec/support/markdown_pact.json +48 -0
  127. data/spec/support/pact_helper.rb +2 -1
  128. data/spec/support/spec_support.rb +7 -0
  129. data/spec/support/test_app_fail.json +11 -2
  130. data/tasks/pact-test.rake +9 -0
  131. metadata +113 -20
  132. data/example/animal-service/db/animals_db.sqlite3 +0 -0
  133. data/lib/pact/consumer/rspec/full_example_description.rb +0 -28
  134. data/lib/pact/matchers/nested_json_diff_decorator.rb +0 -53
  135. data/spec/lib/pact/matchers/diff_decorator_spec.rb +0 -80
  136. data/spec/lib/pact/matchers/nested_json_diff_decorator_spec.rb +0 -48
@@ -1,179 +1,11 @@
1
1
  require 'pact/configuration'
2
2
  require 'pact/consumer/consumer_contract_builders'
3
3
  require 'pact/consumer/consumer_contract_builder'
4
- require 'pact/shared/dsl'
4
+ require 'pact/consumer/configuration/service_consumer'
5
+ require 'pact/consumer/configuration/service_provider'
6
+ require 'pact/consumer/configuration/dsl'
7
+ require 'pact/consumer/configuration/configuration_extensions'
5
8
 
6
- module Pact::Consumer
7
-
8
- module DSL
9
- def service_consumer name, &block
10
- Configuration::ServiceConsumer.build(name, &block)
11
- end
12
- end
13
-
14
- module Configuration
15
-
16
- module ConfigurationExtensions
17
- def add_provider_verification &block
18
- provider_verifications << block
19
- end
20
- def provider_verifications
21
- @provider_verifications ||= []
22
- end
23
- end
24
-
25
- class ServiceConsumer
26
- extend Pact::DSL
27
- attr_accessor :app, :port, :name
28
-
29
- def initialize name
30
- @name = name
31
- @app = nil
32
- @port = nil
33
- end
34
-
35
- dsl do
36
- def app app
37
- self.app = app
38
- end
39
-
40
- def port port
41
- self.port = port
42
- end
43
-
44
- def has_pact_with service_provider_name, &block
45
- ServiceProvider.build(service_provider_name, name, &block)
46
- end
47
- end
48
-
49
- def finalize
50
- validate
51
- register_consumer_app if @app
52
- end
53
-
54
- private
55
-
56
- def validate
57
- raise "Please provide a consumer name" unless (name && !name.empty?)
58
- raise "Please provide a port for the consumer app" if app && !port
59
- end
60
-
61
-
62
- def register_consumer_app
63
- Pact::Consumer::AppManager.instance.register app, port
64
- end
65
- end
66
-
67
-
68
- class ServiceProvider
69
- extend Pact::DSL
70
-
71
- attr_accessor :service, :consumer_name, :name
72
-
73
- def initialize name, consumer_name
74
- @name = name
75
- @service = nil
76
- @consumer_name = consumer_name
77
- end
78
-
79
- dsl do
80
- def mock_service name, &block
81
- self.service = MockService.build(name, consumer_name, self.name, &block)
82
- end
83
- end
84
-
85
- def finalize
86
- validate
87
- end
88
-
89
- private
90
-
91
- def validate
92
- raise "Please configure a service for #{name}" unless service
93
- end
94
-
95
- end
96
-
97
- class MockService
98
- extend Pact::DSL
99
-
100
- attr_accessor :port, :standalone, :verify, :provider_name, :consumer_name
101
-
102
- def initialize name, consumer_name, provider_name
103
- @name = name
104
- @consumer_name = consumer_name
105
- @provider_name = provider_name
106
- @port = nil
107
- @standalone = false
108
- @verify = true
109
- end
110
-
111
- dsl do
112
- def port port
113
- self.port = port
114
- end
115
-
116
- def standalone standalone
117
- self.standalone = standalone
118
- end
119
-
120
- def verify verify
121
- self.verify = verify
122
- end
123
- end
124
-
125
- def finalize
126
- validate
127
- register_mock_service
128
- configure_consumer_contract_builder
129
- end
130
-
131
- private
132
-
133
- def register_mock_service
134
- unless standalone
135
- AppManager.instance.register_mock_service_for provider_name, "http://localhost:#{port}"
136
- end
137
- end
138
-
139
- def configure_consumer_contract_builder
140
- consumer_contract_builder = create_consumer_contract_builder
141
- create_consumer_contract_builders_method consumer_contract_builder
142
- setup_verification(consumer_contract_builder) if verify
143
- consumer_contract_builder
144
- end
145
-
146
- def create_consumer_contract_builder
147
- consumer_contract_builder_fields = {
148
- :consumer_name => consumer_name,
149
- :provider_name => provider_name,
150
- :pactfile_write_mode => Pact.configuration.pactfile_write_mode,
151
- :port => port
152
- }
153
- Pact::Consumer::ConsumerContractBuilder.new consumer_contract_builder_fields
154
- end
155
-
156
- def setup_verification consumer_contract_builder
157
- Pact.configuration.add_provider_verification do | example_description |
158
- consumer_contract_builder.verify example_description
159
- end
160
- end
161
-
162
- # This makes the consumer_contract_builder available via a module method with the given identifier
163
- # as the method name.
164
- # I feel this should be defined somewhere else, but I'm not sure where
165
- def create_consumer_contract_builders_method consumer_contract_builder
166
- Pact::Consumer::ConsumerContractBuilders.send(:define_method, @name.to_sym) do
167
- consumer_contract_builder
168
- end
169
- end
170
-
171
- def validate
172
- raise "Please provide a port for service #{name}" unless port
173
- end
174
- end
175
- end
176
- end
177
9
 
178
10
  Pact.send(:extend, Pact::Consumer::DSL)
179
11
  Pact::Configuration.send(:include, Pact::Consumer::Configuration::ConfigurationExtensions)
@@ -0,0 +1,15 @@
1
+ module Pact
2
+ module Consumer
3
+ module Configuration
4
+
5
+ module ConfigurationExtensions
6
+ def add_provider_verification &block
7
+ provider_verifications << block
8
+ end
9
+ def provider_verifications
10
+ @provider_verifications ||= []
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ require 'pact/consumer/configuration/service_consumer'
2
+
3
+ module Pact
4
+
5
+ module Consumer
6
+ module DSL
7
+ def service_consumer name, &block
8
+ Configuration::ServiceConsumer.build(name, &block)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,89 @@
1
+ require 'pact/consumer/app_manager'
2
+ require 'pact/consumer/consumer_contract_builder'
3
+ require 'pact/consumer/consumer_contract_builders'
4
+
5
+ module Pact
6
+ module Consumer
7
+ module Configuration
8
+ class MockService
9
+
10
+ extend Pact::DSL
11
+
12
+ attr_accessor :port, :standalone, :verify, :provider_name, :consumer_name
13
+
14
+ def initialize name, consumer_name, provider_name
15
+ @name = name
16
+ @consumer_name = consumer_name
17
+ @provider_name = provider_name
18
+ @port = nil
19
+ @standalone = false
20
+ @verify = true
21
+ end
22
+
23
+ dsl do
24
+ def port port
25
+ self.port = port
26
+ end
27
+
28
+ def standalone standalone
29
+ self.standalone = standalone
30
+ end
31
+
32
+ def verify verify
33
+ self.verify = verify
34
+ end
35
+ end
36
+
37
+ def finalize
38
+ validate
39
+ register_mock_service
40
+ configure_consumer_contract_builder
41
+ end
42
+
43
+ private
44
+
45
+ def register_mock_service
46
+ unless standalone
47
+ AppManager.instance.register_mock_service_for provider_name, "http://localhost:#{port}"
48
+ end
49
+ end
50
+
51
+ def configure_consumer_contract_builder
52
+ consumer_contract_builder = create_consumer_contract_builder
53
+ create_consumer_contract_builders_method consumer_contract_builder
54
+ setup_verification(consumer_contract_builder) if verify
55
+ consumer_contract_builder
56
+ end
57
+
58
+ def create_consumer_contract_builder
59
+ consumer_contract_builder_fields = {
60
+ :consumer_name => consumer_name,
61
+ :provider_name => provider_name,
62
+ :pactfile_write_mode => Pact.configuration.pactfile_write_mode,
63
+ :port => port
64
+ }
65
+ Pact::Consumer::ConsumerContractBuilder.new consumer_contract_builder_fields
66
+ end
67
+
68
+ def setup_verification consumer_contract_builder
69
+ Pact.configuration.add_provider_verification do | example_description |
70
+ consumer_contract_builder.verify example_description
71
+ end
72
+ end
73
+
74
+ # This makes the consumer_contract_builder available via a module method with the given identifier
75
+ # as the method name.
76
+ # I feel this should be defined somewhere else, but I'm not sure where
77
+ def create_consumer_contract_builders_method consumer_contract_builder
78
+ Pact::Consumer::ConsumerContractBuilders.send(:define_method, @name.to_sym) do
79
+ consumer_contract_builder
80
+ end
81
+ end
82
+
83
+ def validate
84
+ raise "Please provide a port for service #{name}" unless port
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,51 @@
1
+ require 'pact/shared/dsl'
2
+
3
+ module Pact
4
+ module Consumer
5
+ module Configuration
6
+ class ServiceConsumer
7
+
8
+ extend Pact::DSL
9
+
10
+ attr_accessor :app, :port, :name
11
+
12
+ def initialize name
13
+ @name = name
14
+ @app = nil
15
+ @port = nil
16
+ end
17
+
18
+ dsl do
19
+ def app app
20
+ self.app = app
21
+ end
22
+
23
+ def port port
24
+ self.port = port
25
+ end
26
+
27
+ def has_pact_with service_provider_name, &block
28
+ ServiceProvider.build(service_provider_name, name, &block)
29
+ end
30
+ end
31
+
32
+ def finalize
33
+ validate
34
+ register_consumer_app if @app
35
+ end
36
+
37
+ private
38
+
39
+ def validate
40
+ raise "Please provide a consumer name" unless (name && !name.empty?)
41
+ raise "Please provide a port for the consumer app" if app && !port
42
+ end
43
+
44
+
45
+ def register_consumer_app
46
+ Pact::Consumer::AppManager.instance.register app, port
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ require 'pact/shared/dsl'
2
+ require 'pact/consumer/configuration/mock_service'
3
+
4
+ module Pact
5
+ module Consumer
6
+ module Configuration
7
+ class ServiceProvider
8
+
9
+ extend Pact::DSL
10
+
11
+ attr_accessor :service, :consumer_name, :name
12
+
13
+ def initialize name, consumer_name
14
+ @name = name
15
+ @service = nil
16
+ @consumer_name = consumer_name
17
+ end
18
+
19
+ dsl do
20
+ def mock_service name, &block
21
+ self.service = MockService.build(name, consumer_name, self.name, &block)
22
+ end
23
+ end
24
+
25
+ def finalize
26
+ validate
27
+ end
28
+
29
+ private
30
+
31
+ def validate
32
+ raise "Please configure a service for #{name}" unless service
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+ end
@@ -1,5 +1,3 @@
1
- require 'pact/matchers/diff_decorator'
2
-
3
1
  module Pact
4
2
  module Consumer
5
3
 
@@ -37,7 +35,9 @@ module Pact
37
35
  attr_accessor :candiate_diffs
38
36
 
39
37
  class CandidateDiff
38
+
40
39
  attr_accessor :candidate_interaction, :actual_request
40
+
41
41
  def initialize candidate_interaction, actual_request
42
42
  @candidate_interaction = candidate_interaction
43
43
  @actual_request = actual_request
@@ -56,7 +56,7 @@ module Pact
56
56
  def to_s
57
57
  [
58
58
  "Diff with interaction: #{candidate_interaction.description_with_provider_state_quoted}",
59
- Pact::Matchers::DiffDecorator.new(diff).to_s
59
+ Pact.configuration.diff_formatter.call(diff, {colour: false})
60
60
  ].join("\n")
61
61
  end
62
62
 
@@ -22,8 +22,8 @@ module Pact
22
22
  def respond env
23
23
  interaction = Interaction.from_hash(JSON.load(env['rack.input'].string))
24
24
  interaction_list.add interaction
25
- logger.info "Registered expected interaction #{interaction.request.method_and_path} for #{name}"
26
- logger.ap interaction.as_json
25
+ logger.info "Registered expected interaction #{interaction.request.method_and_path}"
26
+ logger.debug JSON.pretty_generate interaction
27
27
  [200, {}, ['Added interaction']]
28
28
  end
29
29
  end
@@ -30,7 +30,7 @@ module Pact
30
30
  def find_response request_hash
31
31
  actual_request = Request::Actual.from_hash(request_hash)
32
32
  logger.info "#{name} received request #{actual_request.method_and_path}"
33
- logger.ap actual_request.as_json
33
+ logger.debug JSON.pretty_generate actual_request
34
34
  candidate_interactions = interaction_list.find_candidate_interactions actual_request
35
35
  matching_interactions = find_matching_interactions actual_request, from: candidate_interactions
36
36
 
@@ -91,10 +91,9 @@ module Pact
91
91
  end
92
92
 
93
93
  def log_unrecognised_request_and_interaction_diff interaction_mismatch
94
- logger.error "No interaction found on #{name} for #{interaction_mismatch.actual_request.method_and_path}"
94
+ logger.error "No matching interaction found on #{name} for #{interaction_mismatch.actual_request.method_and_path}"
95
95
  logger.error 'Interaction diffs for that route:'
96
- logger.ap(interaction_mismatch.to_hash, :error)
97
- logger.error("Interaction diffs for that route in text format:\n#{interaction_mismatch.to_s}")
96
+ logger.error(interaction_mismatch.to_s)
98
97
  end
99
98
 
100
99
  def handle_unrecognised_request actual_request, candidate_interactions