pact-message 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78d08c5d0ff1f47c7645c15116d76899e296609e415a2bd7c316aecb2f3ab350
4
- data.tar.gz: c306cdc07c7ec261cdb6908d0c5528a934055d71bfd4ca64cddede5d960d698b
3
+ metadata.gz: 9e2884875c85c338522d2113d74c7e742309cdc864180a6c7270bf3f3d31a175
4
+ data.tar.gz: 786c95da06a2c7b44a5eb17c18c7f45b1c52fdbe0cab4d6732ab57d8d49b0954
5
5
  SHA512:
6
- metadata.gz: e96ced52250984fefe42525d870ef3257bbaf16c6021f6b6426cf49eea83b5d31683e481357ceae672833e58fe930cb7b2cab410d8f0d4f1186bd3013153d443
7
- data.tar.gz: 20ef30518e2cf57b1f21e3f2540f4a48858781752318dbe3b2d4dff743830510e83d0335cc59c224a995aacda5860c8a8383bb7c0aa25f60cfde704260ea75da
6
+ metadata.gz: ad49fca208a2fef4107862750d4349ba890354ecf220c497fc3fa192f1d78cd7dee3abba59770023682734e9d5236932d74faf488fe372637181aad81c569550
7
+ data.tar.gz: 4b96ecd3a271135ede66c3d2f492030e4daa045362a8db507b236e6bad0e4e54aaaff064703dcbdf1970d7e73cb0673b45c0f8f49895726e6aee9bc3f58ae63e
@@ -23,15 +23,15 @@ jobs:
23
23
  needs: test
24
24
  runs-on: ubuntu-latest
25
25
  outputs:
26
- gem_name: ${{ steps.release.outputs.gem_name }}
27
- version: ${{ steps.release.outputs.version }}
28
- increment: ${{ steps.release.outputs.increment }}
26
+ gem_name: ${{ steps.release-gem.outputs.gem_name }}
27
+ version: ${{ steps.release-gem.outputs.version }}
28
+ increment: ${{ steps.release-gem.outputs.increment }}
29
29
  steps:
30
30
  - uses: actions/checkout@v2
31
31
  with:
32
32
  fetch-depth: 0
33
33
  - uses: pact-foundation/release-gem@v0.0.11
34
- id: release
34
+ id: release-gem
35
35
  env:
36
36
  GEM_HOST_API_KEY: '${{ secrets.RUBYGEMS_API_KEY }}'
37
37
  GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
data/.gitignore CHANGED
@@ -12,3 +12,4 @@ spec/pacts/zoo_consumer-zoo_provider.json
12
12
 
13
13
  # rspec failure tracking
14
14
  .rspec_status
15
+ spec/pacts/
@@ -1,3 +1,14 @@
1
+ <a name="v0.9.0"></a>
2
+ ### v0.9.0 (2020-11-04)
3
+
4
+ #### Features
5
+
6
+ * allow pact dir to be configured ([f2f9626](/../../commit/f2f9626))
7
+ * verify that each message has been yielded ([1d4d92c](/../../commit/1d4d92c))
8
+
9
+ * **consumer**
10
+ * only update pact if test suite passes ([e99276d](/../../commit/e99276d))
11
+
1
12
  <a name="v0.8.0"></a>
2
13
  ### v0.8.0 (2020-09-28)
3
14
 
@@ -31,6 +31,10 @@ module Pact
31
31
  end
32
32
  end
33
33
 
34
+ def reified_contents_hash
35
+ Pact::Reification.from_term(contents)
36
+ end
37
+
34
38
  def contents
35
39
  @contents
36
40
  end
@@ -12,10 +12,10 @@ module Pact
12
12
  desc 'update MESSAGE_JSON', 'Update a pact with the given message, or create the pact if it does not exist. The MESSAGE_JSON may be in the legacy Ruby JSON format or the v2+ format.'
13
13
  def update(message)
14
14
  require 'pact/message'
15
- require 'pact/message/consumer/update_pact'
15
+ require 'pact/message/consumer/write_pact'
16
16
  pact_specification_version = Pact::SpecificationVersion.new(options.pact_specification_version)
17
17
  message = Pact::Message.from_hash(JSON.load(message), { pact_specification_version: pact_specification_version })
18
- Pact::Message::Consumer::UpdatePact.call(message, options.pact_dir, options.consumer, options.provider, options.pact_specification_version)
18
+ Pact::Message::Consumer::WritePact.call(message, options.pact_dir, options.consumer, options.provider, options.pact_specification_version, :update)
19
19
  end
20
20
 
21
21
  desc 'reify', "Take a JSON document with embedded pact matchers and return a concrete example"
@@ -1,6 +1,6 @@
1
1
  require 'pact/message/consumer/consumer_contract_builder'
2
2
  require 'pact/message/consumer/consumer_contract_builders'
3
- # require 'pact/consumer/world'
3
+ require 'pact/message/consumer/world'
4
4
 
5
5
  module Pact
6
6
  module Message
@@ -40,11 +40,11 @@ module Pact
40
40
 
41
41
  def create_consumer_contract_builder
42
42
  consumer_contract_builder_fields = {
43
- :consumer_name => consumer_name,
44
- :provider_name => provider_name,
43
+ consumer_name: consumer_name,
44
+ provider_name: provider_name,
45
+ pact_specification_version: pact_specification_version,
46
+ pact_dir: Pact.configuration.pact_dir
45
47
  }
46
- # :pactfile_write_mode => Pact.configuration.pactfile_write_mode,
47
- # :pact_dir => Pact.configuration.pact_dir
48
48
  Pact::Message::Consumer::ConsumerContractBuilder.new consumer_contract_builder_fields
49
49
  end
50
50
 
@@ -58,7 +58,8 @@ module Pact
58
58
  Pact::Message::Consumer::ConsumerContractBuilders.send(:define_method, @name.to_sym) do
59
59
  consumer_contract_builder
60
60
  end
61
- # Pact.consumer_world.add_consumer_contract_builder consumer_contract_builder
61
+
62
+ Pact::Message.consumer_world.add_consumer_contract_builder consumer_contract_builder
62
63
  end
63
64
  end
64
65
  end
@@ -18,9 +18,13 @@ module Pact
18
18
  end
19
19
 
20
20
  dsl do
21
- def builder builder_name, &block
21
+ def mock_provider(builder_name, &block)
22
22
  self.builder = MessageBuilder.build(builder_name, consumer_name, name, &block)
23
23
  end
24
+
25
+ def builder(builder_name, &block)
26
+ expectation_builder(builder_name, &block)
27
+ end
24
28
  end
25
29
 
26
30
  def finalize
@@ -1,5 +1,6 @@
1
1
  require 'pact/message/consumer/interaction_builder'
2
- require 'pact/message/consumer/update_pact'
2
+ require 'pact/message/consumer/write_pact'
3
+ require 'pact/errors'
3
4
 
4
5
  module Pact
5
6
  module Message
@@ -10,11 +11,19 @@ module Pact
10
11
  @interaction_builder = nil
11
12
  @consumer_name = attributes[:consumer_name]
12
13
  @provider_name = attributes[:provider_name]
14
+ @pact_specification_version = attributes[:pact_specification_version]
15
+ @pact_dir = attributes[:pact_dir]
13
16
  @interactions = []
17
+ @yielded_interaction = false
14
18
  end
15
19
 
16
- def given(provider_state)
17
- interaction_builder.given(provider_state)
20
+ def reset
21
+ @interaction_builder = nil
22
+ @yielded_interaction = false
23
+ end
24
+
25
+ def given(provider_state, params = {})
26
+ interaction_builder.given(provider_state, params)
18
27
  end
19
28
 
20
29
  def is_expected_to_send(description)
@@ -22,27 +31,59 @@ module Pact
22
31
  end
23
32
 
24
33
  def send_message_string
25
- yield contents.reified_contents_string if block_given?
34
+ if interaction_builder?
35
+ if block_given?
36
+ @yielded_interaction = true
37
+ yield interaction_builder.interaction.contents.reified_contents_string
38
+ end
39
+ else
40
+ raise Pact::Error.new("No message expectation has been defined")
41
+ end
42
+ end
43
+
44
+ def send_message_hash
45
+ if interaction_builder?
46
+ if block_given?
47
+ @yielded_interaction = true
48
+ yield interaction_builder.interaction.contents.reified_contents_hash
49
+ end
50
+ else
51
+ raise Pact::Error.new("No message expectation has been defined")
52
+ end
26
53
  end
27
54
 
28
55
  def handle_interaction_fully_defined(interaction)
29
56
  @contents = interaction.contents
30
57
  @contents_string = interaction.contents.to_s
31
- @interactions << interaction
32
- @interaction_builder = nil
33
- # TODO pull these from pact config
34
- Pact::Message::Consumer::UpdatePact.call(interaction, "./spec/pacts", consumer_name, provider_name, "2.0.0")
35
58
  end
36
59
 
37
60
  def verify example_description
38
- #
39
- # TODO check that message was actually yielded
61
+ # There may be multiple message providers defined, and not every one of them
62
+ # has to define a message for every test.
63
+ if interaction_builder?
64
+ if yielded_interaction?
65
+ interactions << interaction_builder.interaction
66
+ else
67
+ raise Pact::Error.new("`send_message_string` was not called for message \"#{interaction_builder.interaction.description}\"")
68
+ end
69
+ end
70
+ end
71
+
72
+ def write_pact
73
+ Pact::Message::Consumer::WritePact.call(interactions, pact_dir, consumer_name, provider_name, pact_specification_version, :overwrite)
40
74
  end
41
75
 
42
76
  private
43
77
 
44
- attr_writer :interaction_builder
45
- attr_accessor :consumer_name, :provider_name, :consumer_contract_details, :contents
78
+ attr_accessor :consumer_name, :provider_name, :consumer_contract_details, :contents, :interactions, :pact_specification_version, :pact_dir
79
+
80
+ def interaction_builder?
81
+ !!@interaction_builder
82
+ end
83
+
84
+ def yielded_interaction?
85
+ @yielded_interaction
86
+ end
46
87
 
47
88
  def interaction_builder
48
89
  @interaction_builder ||=
@@ -17,13 +17,17 @@ module Pact
17
17
  self
18
18
  end
19
19
 
20
- def given provider_state
21
- @interaction.provider_state = provider_state.nil? ? nil : provider_state.to_s
20
+ def given name, params = {}
21
+ if name
22
+ @interaction.provider_states << Pact::ProviderState.new(name, params)
23
+ end
22
24
  self
23
25
  end
24
26
 
27
+ alias_method :and, :given
28
+
25
29
  def with_metadata(object)
26
- # TODO implement this
30
+ interaction.metadata = object
27
31
  self
28
32
  end
29
33
 
@@ -17,7 +17,9 @@ module Pact
17
17
  hash[:providerStates] = provider_states
18
18
  hash[:contents] = extract_contents
19
19
  hash[:matchingRules] = extract_matching_rules
20
- hash[:metaData] = message.metadata || {}
20
+ if message.metadata
21
+ hash[:metaData] = message.metadata
22
+ end
21
23
  fix_all_the_things hash
22
24
  end
23
25
 
@@ -42,9 +44,14 @@ module Pact
42
44
  end
43
45
 
44
46
  def extract_matching_rules
45
- {
46
- body: Pact::MatchingRules.extract(message.contents.contents, pact_specification_version: pact_specification_version)
47
- }
47
+ body_matching_rules = Pact::MatchingRules.extract(message.contents.contents, pact_specification_version: pact_specification_version)
48
+ if body_matching_rules.any?
49
+ {
50
+ body: body_matching_rules
51
+ }
52
+ else
53
+ {}
54
+ end
48
55
  end
49
56
 
50
57
  def pact_specification_version
@@ -20,7 +20,15 @@ hooks = Pact::Message::Consumer::SpecHooks.new
20
20
  RSpec.configure do |config|
21
21
  config.include Pact::Message::Consumer::RSpec, :pact => :message
22
22
 
23
- config.after :each, :pact => true do | example |
23
+ config.before :each, :pact => :message do | example |
24
+ hooks.before_each Pact::RSpec.full_description(example)
25
+ end
26
+
27
+ config.after :each, :pact => :message do | example |
24
28
  hooks.after_each Pact::RSpec.full_description(example)
25
29
  end
30
+
31
+ config.after :all do
32
+ hooks.after_suite
33
+ end
26
34
  end
@@ -1,12 +1,25 @@
1
+ require 'pact/message/consumer/world'
2
+
1
3
  module Pact
2
4
  module Message
3
5
  module Consumer
4
6
  class SpecHooks
7
+ def before_each example_description
8
+ Pact::Message.consumer_world.register_pact_example_ran
9
+ Pact::Message.consumer_world.consumer_contract_builders.each(&:reset)
10
+ end
11
+
5
12
  def after_each example_description
6
13
  Pact.configuration.message_provider_verifications.each do | message_provider_verification |
7
14
  message_provider_verification.call example_description
8
15
  end
9
16
  end
17
+
18
+ def after_suite
19
+ if Pact::Message.consumer_world.any_pact_examples_ran?
20
+ Pact::Message.consumer_world.consumer_contract_builders.each(&:write_pact)
21
+ end
22
+ end
10
23
  end
11
24
  end
12
25
  end
@@ -0,0 +1,36 @@
1
+ module Pact
2
+ module Message
3
+ def self.consumer_world
4
+ @consumer_world ||= 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
+ def initialize
15
+ @any_pact_examples_ran = false
16
+ end
17
+
18
+ def consumer_contract_builders
19
+ @consumer_contract_builders ||= []
20
+ end
21
+
22
+ def add_consumer_contract_builder consumer_contract_builder
23
+ consumer_contract_builders << consumer_contract_builder
24
+ end
25
+
26
+ def register_pact_example_ran
27
+ @any_pact_examples_ran = true
28
+ end
29
+
30
+ def any_pact_examples_ran?
31
+ @any_pact_examples_ran
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -4,26 +4,27 @@ require 'pact/message/consumer/consumer_contract_decorator'
4
4
  module Pact
5
5
  module Message
6
6
  module Consumer
7
- class UpdatePact
7
+ class WritePact
8
8
 
9
- def initialize message, pact_dir, consumer_name, provider_name, pact_specification_version
9
+ def initialize messages, pact_dir, consumer_name, provider_name, pact_specification_version, pactfile_write_mode
10
10
  @pact_dir = pact_dir
11
- @message = message
11
+ @messages = messages
12
12
  @consumer_name = consumer_name
13
13
  @provider_name = provider_name
14
14
  @pact_specification_version = pact_specification_version
15
+ @pactfile_write_mode = pactfile_write_mode
15
16
  end
16
17
 
17
- def self.call(message, pact_dir, consumer_name, provider_name, pact_specification_version)
18
- new(message, pact_dir, consumer_name, provider_name, pact_specification_version).call
18
+ def self.call(messages, pact_dir, consumer_name, provider_name, pact_specification_version, pactfile_write_mode)
19
+ new(messages, pact_dir, consumer_name, provider_name, pact_specification_version, pactfile_write_mode).call
19
20
  end
20
21
 
21
22
  def call
22
23
  details = {
23
- consumer: {name: consumer_name},
24
- provider: {name: provider_name},
25
- interactions: [message],
26
- pactfile_write_mode: :update,
24
+ consumer: { name: consumer_name },
25
+ provider: { name: provider_name },
26
+ interactions: [*messages],
27
+ pactfile_write_mode: pactfile_write_mode,
27
28
  pact_dir: pact_dir,
28
29
  pact_specification_version: pact_specification_version,
29
30
  error_stream: StringIO.new,
@@ -36,7 +37,7 @@ module Pact
36
37
 
37
38
  private
38
39
 
39
- attr_reader :message, :pact_dir, :consumer_name, :provider_name, :pact_specification_version
40
+ attr_reader :messages, :pact_dir, :consumer_name, :provider_name, :pact_specification_version, :pactfile_write_mode
40
41
  end
41
42
  end
42
43
  end
@@ -1,5 +1,5 @@
1
1
  module Pact
2
2
  module Message
3
- VERSION = "0.8.0"
3
+ VERSION = "0.9.0"
4
4
  end
5
5
  end
@@ -0,0 +1 @@
1
+ require 'pact/message'
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_runtime_dependency "pact-mock_service", "~> 3.1"
37
37
  spec.add_runtime_dependency "thor", "~> 0.20"
38
38
 
39
- spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rake", "~> 12.3", ">= 12.3.3"
40
40
  spec.add_development_dependency "rspec", "~> 3.0"
41
41
  spec.add_development_dependency "pry-byebug"
42
42
  spec.add_development_dependency 'conventional-changelog', '~>1.2'
@@ -0,0 +1,60 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ ZOO_PACT_FILE_PATH = "spec/pacts/zoo_consumer-zoo_provider.json"
4
+
5
+ RSpec::Core::RakeTask.new(:pass) do | task |
6
+ task.pattern = "spec/features/create_message_pact_spec.rb"
7
+ end
8
+
9
+ RSpec::Core::RakeTask.new(:fail) do | task |
10
+ task.pattern = "spec/features/create_message_pact_with_failure_test.rb"
11
+ end
12
+
13
+ task :pass_writes_pact_file do
14
+ require 'json'
15
+ puts "Ensuring that pact file is written for successful test suites"
16
+ FileUtils.rm_rf(ZOO_PACT_FILE_PATH)
17
+ Rake::Task['pass'].execute
18
+ if !File.exist?(ZOO_PACT_FILE_PATH)
19
+ raise "Expected pact file to be written at #{ZOO_PACT_FILE_PATH}"
20
+ end
21
+
22
+ pact_hash = JSON.parse(File.read(ZOO_PACT_FILE_PATH))
23
+ if pact_hash['messages'].size < 2
24
+ raise "Expected pact file to contain more than 1 message"
25
+ end
26
+ end
27
+
28
+ task :fail_does_not_write_pact_file do
29
+ puts "Ensuring that pact file is NOT written for failed test suites"
30
+ FileUtils.rm_rf(ZOO_PACT_FILE_PATH)
31
+ expect_to_fail('bundle exec rake fail')
32
+ if File.exist?(ZOO_PACT_FILE_PATH)
33
+ raise "Expected pact file NOT to be written at #{ZOO_PACT_FILE_PATH}"
34
+ end
35
+ end
36
+
37
+ task :default => [:pass_writes_pact_file, :fail_does_not_write_pact_file]
38
+
39
+ def expect_to_fail command, options = {}
40
+ success = execute_command command, options
41
+ fail "Expected '#{command}' to fail" if success
42
+ end
43
+
44
+ def execute_command command, options
45
+ require 'open3'
46
+ result = nil
47
+ Open3.popen3(command) {|stdin, stdout, stderr, wait_thr|
48
+ result = wait_thr.value
49
+ ensure_patterns_present(command, options, stdout, stderr) if options[:with]
50
+ }
51
+ result.success?
52
+ end
53
+
54
+ def ensure_patterns_present command, options, stdout, stderr
55
+ require 'term/ansicolor'
56
+ output = stdout.read + stderr.read
57
+ options[:with].each do | pattern |
58
+ raise (::Term::ANSIColor.red("Could not find #{pattern.inspect} in output of #{command}") + "\n\n#{output}") unless output =~ pattern
59
+ end
60
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact-message
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Beth Skurrie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-28 00:00:00.000000000 Z
11
+ date: 2020-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pact-support
@@ -58,14 +58,20 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '12.3'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 12.3.3
62
65
  type: :development
63
66
  prerelease: false
64
67
  version_requirements: !ruby/object:Gem::Requirement
65
68
  requirements:
66
69
  - - "~>"
67
70
  - !ruby/object:Gem::Version
68
- version: '10.0'
71
+ version: '12.3'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 12.3.3
69
75
  - !ruby/object:Gem::Dependency
70
76
  name: rspec
71
77
  requirement: !ruby/object:Gem::Requirement
@@ -165,9 +171,11 @@ files:
165
171
  - lib/pact/message/consumer/interaction_decorator.rb
166
172
  - lib/pact/message/consumer/rspec.rb
167
173
  - lib/pact/message/consumer/spec_hooks.rb
168
- - lib/pact/message/consumer/update_pact.rb
174
+ - lib/pact/message/consumer/world.rb
175
+ - lib/pact/message/consumer/write_pact.rb
169
176
  - lib/pact/message/consumer_contract_parser.rb
170
177
  - lib/pact/message/version.rb
178
+ - lib/pact/pact-message.rb
171
179
  - pact-message.gemspec
172
180
  - script/docker-functions
173
181
  - script/functions
@@ -177,6 +185,7 @@ files:
177
185
  - script/trigger-release.sh
178
186
  - script/update-pact.sh
179
187
  - tasks/release.rake
188
+ - tasks/test.rake
180
189
  homepage: http://pact.io
181
190
  licenses:
182
191
  - MIT