diff --git a/lib/pact/provider/generator/boolean.rb b/lib/pact/provider/generator/boolean.rb new file mode 100644 index 00000000..499e326a --- /dev/null +++ b/lib/pact/provider/generator/boolean.rb @@ -0,0 +1,16 @@ +module Pact + module Provider + module Generator + # Boolean provides the boolean generator which will give a true or false value + class Boolean + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'Boolean' + end + + def call(_hash, _params = nil, _example_value = nil) + [true, false].sample + end + end + end + end +end diff --git a/lib/pact/provider/generator/date.rb b/lib/pact/provider/generator/date.rb new file mode 100644 index 00000000..7b05c247 --- /dev/null +++ b/lib/pact/provider/generator/date.rb @@ -0,0 +1,64 @@ +require 'date' + +module Pact + module Provider + module Generator + # Date provides the time generator which will give the current date in the defined format + class Date + def can_generate?(hash) + hash.key?('type') && hash['type'] == type + end + + def call(hash, _params = nil, _example_value = nil) + format = hash['format'] || default_format + ::Time.now.strftime(convert_from_java_simple_date_format(format)) + end + + def type + 'Date' + end + + def default_format + 'yyyy-MM-dd' + end + + # Format for the pact specficiation should be the Java DateTimeFormmater + # This tries to convert to something Ruby can format. + def convert_from_java_simple_date_format(format) + # Year + format.sub!(/(?= 0 + if position.positive? + # add string + return_string.push(buffer[0...position]) + end + end_position = buffer.index(END_EXPRESSION, position) + raise 'Missing closing brace in expression string' if !end_position || end_position.negative? + + variable = buffer[position + 2...end_position] + + if !params[variable] + logger.info "Could not subsitute provider state key #{variable}, have #{params}" + end + + expression = params[variable] || '' + return_string.push(expression) + + buffer = buffer[end_position + 1...-1] + position = buffer.index(START_EXPRESSION) + end + + return_string.join('') + end + end + end + end +end diff --git a/lib/pact/provider/generator/random_decimal.rb b/lib/pact/provider/generator/random_decimal.rb new file mode 100644 index 00000000..5a756552 --- /dev/null +++ b/lib/pact/provider/generator/random_decimal.rb @@ -0,0 +1,39 @@ +require 'bigdecimal' + +module Pact + module Provider + module Generator + # RandomDecimal provides the random decimal generator which will generate a decimal value of digits length + class RandomDecimal + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomDecimal' + end + + def call(hash, _params = nil, _example_value = nil) + digits = hash['digits'] || 6 + + raise 'RandomDecimalGenerator digits must be > 0, got $digits' if digits < 1 + + return rand(0..9) if digits == 1 + + return rand(0..9) + rand(1..9) / 10 if digits == 2 + + pos = rand(1..digits - 1) + precision = digits - pos + integers = '' + decimals = '' + while pos.positive? + integers += String(rand(1..9)) + pos -= 1 + end + while precision.positive? + decimals += String(rand(1..9)) + precision -= 1 + end + + Float("#{integers}.#{decimals}") + end + end + end + end +end diff --git a/lib/pact/provider/generator/random_hexadecimal.rb b/lib/pact/provider/generator/random_hexadecimal.rb new file mode 100644 index 00000000..f2e4f4db --- /dev/null +++ b/lib/pact/provider/generator/random_hexadecimal.rb @@ -0,0 +1,21 @@ +require 'securerandom' + +module Pact + module Provider + module Generator + # RandomHexadecimal provides the random hexadecimal generator which will generate a hexadecimal + class RandomHexadecimal + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomHexadecimal' + end + + def call(hash, _params = nil, _example_value = nil) + digits = hash['digits'] || 8 + bytes = (digits / 2).ceil + string = SecureRandom.hex(bytes) + string[0, digits] + end + end + end + end +end diff --git a/lib/pact/provider/generator/random_int.rb b/lib/pact/provider/generator/random_int.rb new file mode 100644 index 00000000..5f749359 --- /dev/null +++ b/lib/pact/provider/generator/random_int.rb @@ -0,0 +1,18 @@ +module Pact + module Provider + module Generator + # RandomInt provides the random int generator which generate a random integer, with a min/max + class RandomInt + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomInt' + end + + def call(hash, _params = nil, _example_value = nil) + min = hash['min'] || 0 + max = hash['max'] || 2_147_483_647 + rand(min..max) + end + end + end + end +end diff --git a/lib/pact/provider/generator/random_string.rb b/lib/pact/provider/generator/random_string.rb new file mode 100644 index 00000000..5c56b08d --- /dev/null +++ b/lib/pact/provider/generator/random_string.rb @@ -0,0 +1,18 @@ +module Pact + module Provider + module Generator + # RandomString provides the random string generator which generate a random string of size length + class RandomString + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomString' + end + + def call(hash, _params = nil, _example_value = nil) + size = hash['size'] || 20 + string = rand(36**(size + 2)).to_s(36) + string[0, size] + end + end + end + end +end diff --git a/lib/pact/provider/generator/regex.rb b/lib/pact/provider/generator/regex.rb new file mode 100644 index 00000000..1415cf87 --- /dev/null +++ b/lib/pact/provider/generator/regex.rb @@ -0,0 +1,19 @@ +require 'string_pattern' + +module Pact + module Provider + module Generator + # Regex provides the regex generator which will generate a value based on the regex pattern provided + class Regex + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'Regex' + end + + def call(hash, _params = nil, _example_value = nil) + pattern = hash['pattern'] || '' + StringPattern.generate(Regexp.new(pattern)) + end + end + end + end +end diff --git a/lib/pact/provider/generator/time.rb b/lib/pact/provider/generator/time.rb new file mode 100644 index 00000000..0db4d214 --- /dev/null +++ b/lib/pact/provider/generator/time.rb @@ -0,0 +1,18 @@ +require 'date' + +module Pact + module Provider + module Generator + # Time provides the time generator which will give the current time in the defined format + class Time < Date + def type + 'Time' + end + + def default_format + 'HH:mm' + end + end + end + end +end diff --git a/lib/pact/provider/generator/uuid.rb b/lib/pact/provider/generator/uuid.rb new file mode 100644 index 00000000..f1441340 --- /dev/null +++ b/lib/pact/provider/generator/uuid.rb @@ -0,0 +1,21 @@ +require 'securerandom' + +module Pact + module Provider + module Generator + # Uuid provides the uuid generator + class Uuid + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'Uuid' + end + + # If we had the example value, we could determine what type of uuid + # to send, this is what pact-jvm does + # See https://github.com/pact-foundation/pact-jvm/blob/master/core/model/src/main/kotlin/au/com/dius/pact/core/model/generators/Generator.kt + def call(_hash, _params = nil, _example_value = nil) + SecureRandom.uuid + end + end + end + end +end diff --git a/lib/pact/provider/generators.rb b/lib/pact/provider/generators.rb new file mode 100644 index 00000000..2cd77cdb --- /dev/null +++ b/lib/pact/provider/generators.rb @@ -0,0 +1,66 @@ +require 'pact/provider/generator/boolean' +require 'pact/provider/generator/date' +require 'pact/provider/generator/datetime' +require 'pact/provider/generator/provider_state' +require 'pact/provider/generator/random_decimal' +require 'pact/provider/generator/random_hexadecimal' +require 'pact/provider/generator/random_int' +require 'pact/provider/generator/random_string' +require 'pact/provider/generator/regex' +require 'pact/provider/generator/time' +require 'pact/provider/generator/uuid' +require 'pact/matching_rules/jsonpath' +require 'pact/matching_rules/v3/extract' +require 'jsonpath' + +module Pact + module Provider + class Generators + def self.add_generator(generator) + generators.unshift(generator) + end + + def self.generators + @generators ||= [] + end + + def self.execute_generators(object, state_params = nil, example_value = nil) + generators.each do |parser| + return parser.call(object, state_params, example_value) if parser.can_generate?(object) + end + + raise Pact::UnrecognizePactFormatError, "This document does not use a recognised Pact generator: #{object}" + end + + def self.apply_generators(expected_request, component, example_value, state_params) + # Latest pact-support is required to have generators exposed + if expected_request.methods.include?(:generators) && expected_request.generators[component] + # Some component will have single generator without selectors, i.e. path + generators = expected_request.generators[component] + if generators.is_a?(Hash) && generators.key?('type') + return execute_generators(generators, state_params, example_value) + end + + generators.each do |selector, generator| + val = JsonPath.new(selector).on(example_value) + replace = execute_generators(generator, state_params, val) + example_value = JsonPath.for(example_value).gsub(selector) { |_v| replace }.to_hash + end + end + example_value + end + + add_generator(Generator::Boolean.new) + add_generator(Generator::Date.new) + add_generator(Generator::DateTime.new) + add_generator(Generator::ProviderState.new) + add_generator(Generator::RandomDecimal.new) + add_generator(Generator::RandomHexadecimal.new) + add_generator(Generator::RandomInt.new) + add_generator(Generator::RandomString.new) + add_generator(Generator::Regex.new) + add_generator(Generator::Time.new) + add_generator(Generator::Uuid.new) + end + end +end diff --git a/lib/pact/provider/request.rb b/lib/pact/provider/request.rb index ad4b1998..561e24a6 100644 --- a/lib/pact/provider/request.rb +++ b/lib/pact/provider/request.rb @@ -1,6 +1,7 @@ require 'json' require 'pact/reification' require 'pact/shared/null_expectation' +require 'pact/provider/generators' module Pact module Provider @@ -10,8 +11,9 @@ class Replayable # See https://github.com/rack/rack/blob/e7d741c6282ca4cf4e01506f5681e6e6b14c0b32/SPEC#L87-89 NO_HTTP_PREFIX = ["CONTENT-TYPE", "CONTENT-LENGTH"] - def initialize expected_request + def initialize expected_request, state_params = nil @expected_request = expected_request + @state_params = state_params end def method @@ -19,7 +21,7 @@ def method end def path - expected_request.full_path + Pact::Provider::Generators.apply_generators(expected_request, "path", expected_request.full_path, @state_params) end def body @@ -27,17 +29,20 @@ def body when String then expected_request.body when NullExpectation then '' else - reified_body + Pact::Provider::Generators.apply_generators(expected_request, "body", reified_body, @state_params) end end def headers request_headers = {} return request_headers if expected_request.headers.is_a?(Pact::NullExpectation) + expected_request.headers.each do |key, value| - request_headers[rack_request_header_for(key)] = Pact::Reification.from_term(value) + request_headers[key] = Pact::Reification.from_term(value) end - request_headers + + request_headers = Pact::Provider::Generators.apply_generators(expected_request, "header", request_headers, @state_params) + request_headers.map{ |key,value| [rack_request_header_for(key), value]}.to_h end private diff --git a/lib/pact/provider/rspec.rb b/lib/pact/provider/rspec.rb index a6e7372c..b498def5 100644 --- a/lib/pact/provider/rspec.rb +++ b/lib/pact/provider/rspec.rb @@ -25,6 +25,7 @@ def honour_pactfile pact_source, pact_json, options pact_uri = pact_source.uri Pact.configuration.output_stream.puts "INFO: Reading pact at #{pact_uri}" consumer_contract = Pact::ConsumerContract.from_json(pact_json) + suffix = pact_uri.metadata[:pending] ? " [PENDING]": "" example_group_description = "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}#{suffix}" example_group_metadata = { pactfile_uri: pact_uri, pact_criteria: options[:criteria] } @@ -77,7 +78,6 @@ def describe_interaction_with_provider_state interaction, options end def describe_interaction interaction, options - # pact_uri and pact_interaction are used by # Pact::Provider::RSpec::PactBrokerFormatter @@ -103,8 +103,9 @@ def describe_interaction interaction, options before do | example | interaction_context.run_once :before do Pact.configuration.logger.info "Running example '#{Pact::RSpec.full_description(example)}'" - set_up_provider_states interaction.provider_states, options[:consumer] - replay_interaction interaction, options[:request_customizer] + provider_states_result = set_up_provider_states interaction.provider_states, options[:consumer] + state_params = provider_states_result[interaction.provider_state]; + replay_interaction interaction, options[:request_customizer], state_params interaction_context.last_response = last_response end end @@ -129,6 +130,7 @@ def describe_message expected_response, interaction_context include Pact::RSpec::Matchers extend Pact::Matchers::Messages + let(:expected_contents) { expected_response.body[:contents].as_json } let(:response) { interaction_context.last_response } let(:differ) { Pact.configuration.body_differ_for_content_type diff_content_type } diff --git a/lib/pact/provider/test_methods.rb b/lib/pact/provider/test_methods.rb index f27466af..1619633d 100644 --- a/lib/pact/provider/test_methods.rb +++ b/lib/pact/provider/test_methods.rb @@ -14,8 +14,8 @@ module TestMethods include Pact::Logging include Rack::Test::Methods - def replay_interaction interaction, request_customizer = nil - request = Request::Replayable.new(interaction.request) + def replay_interaction interaction, request_customizer = nil, state_params = nil + request = Request::Replayable.new(interaction.request, state_params) request = request_customizer.call(request, interaction) if request_customizer args = [request.path, request.body, request.headers] @@ -42,11 +42,17 @@ def parse_body_from_response rack_response end def set_up_provider_states provider_states, consumer, options = {} + provider_states_result = {}; # If there are no provider state, execute with an nil state to ensure global and base states are executed Pact.configuration.provider_state_set_up.call(nil, consumer, options) if provider_states.nil? || provider_states.empty? provider_states.each do | provider_state | - Pact.configuration.provider_state_set_up.call(provider_state.name, consumer, options.merge(params: provider_state.params)) + result = Pact.configuration.provider_state_set_up.call(provider_state.name, consumer, options.merge(params: provider_state.params)) + if result.is_a?(Hash) + provider_states_result[provider_state.name] = result + end end + + provider_states_result end def tear_down_provider_states provider_states, consumer, options = {} diff --git a/pact.gemspec b/pact.gemspec index 3e293377..d0fa6e50 100644 --- a/pact.gemspec +++ b/pact.gemspec @@ -31,8 +31,10 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency 'thor', '>= 0.20', '< 2.0' gem.add_runtime_dependency 'webrick', '~> 1.8' gem.add_runtime_dependency "rainbow", '~> 3.1' + gem.add_runtime_dependency 'string_pattern', '~> 2.0' + gem.add_runtime_dependency 'jsonpath', '~> 1.0' - gem.add_runtime_dependency 'pact-support', '~> 1.16', '>= 1.16.9' + gem.add_runtime_dependency 'pact-support', '~> 1.19', '>= 1.19.0' gem.add_runtime_dependency 'pact-mock_service', '~> 3.0', '>= 3.3.1' gem.add_development_dependency 'rake', '~> 13.0' diff --git a/spec/lib/pact/provider/generator/boolean_spec.rb b/spec/lib/pact/provider/generator/boolean_spec.rb new file mode 100644 index 00000000..0ef0d7e0 --- /dev/null +++ b/spec/lib/pact/provider/generator/boolean_spec.rb @@ -0,0 +1,20 @@ +require 'pact/provider/generator/boolean' + +describe Pact::Provider::Generator::Boolean do + generator = Pact::Provider::Generator::Boolean.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Boolean' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Boolean' } + expect(generator.call(hash)).to eq(true).or eq(false) + end +end diff --git a/spec/lib/pact/provider/generator/date_spec.rb b/spec/lib/pact/provider/generator/date_spec.rb new file mode 100644 index 00000000..46b32d16 --- /dev/null +++ b/spec/lib/pact/provider/generator/date_spec.rb @@ -0,0 +1,20 @@ +require 'pact/provider/generator/date' + +describe Pact::Provider::Generator::Date do + generator = Pact::Provider::Generator::Date.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Date' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Date' } + expect(generator.call(hash).length).to eq(10) + end +end diff --git a/spec/lib/pact/provider/generator/datetime_spec.rb b/spec/lib/pact/provider/generator/datetime_spec.rb new file mode 100644 index 00000000..32c8c1b5 --- /dev/null +++ b/spec/lib/pact/provider/generator/datetime_spec.rb @@ -0,0 +1,21 @@ +require 'pact/provider/generator/datetime' + +describe Pact::Provider::Generator::DateTime do + generator = Pact::Provider::Generator::DateTime.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'DateTime' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'DateTime' } + p generator.call(hash) + expect(generator.call(hash).length).to eq(16) + end +end diff --git a/spec/lib/pact/provider/generator/provider_state_spec.rb b/spec/lib/pact/provider/generator/provider_state_spec.rb new file mode 100644 index 00000000..3e3d4519 --- /dev/null +++ b/spec/lib/pact/provider/generator/provider_state_spec.rb @@ -0,0 +1,37 @@ +require 'pact/provider/generator/provider_state' + +describe Pact::Provider::Generator::ProviderState do + generator = Pact::Provider::Generator::ProviderState.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'ProviderState' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call without params' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + expect(generator.call(hash)).to eq 'Bearer ' + end + + it 'call with correct params' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + params = { 'access_token' => 'ABC' } + expect(generator.call(hash, params)).to eq 'Bearer ABC' + end + + it 'call with wrong params' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + params = { 'refresh_token' => 'ABC' } + expect(generator.call(hash, params)).to eq 'Bearer ' + end + + it 'call with incomplete expression' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token' } + expect { generator.call(hash) }.to raise_error('Missing closing brace in expression string') + end +end diff --git a/spec/lib/pact/provider/generator/random_decimal_spec.rb b/spec/lib/pact/provider/generator/random_decimal_spec.rb new file mode 100644 index 00000000..eb495367 --- /dev/null +++ b/spec/lib/pact/provider/generator/random_decimal_spec.rb @@ -0,0 +1,27 @@ +require 'pact/provider/generator/random_decimal' + +describe Pact::Provider::Generator::RandomDecimal do + generator = Pact::Provider::Generator::RandomDecimal.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomDecimal' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomDecimal' } + value = generator.call(hash) + expect(String(value).length).to eq 7 + end + + it 'call with digits' do + hash = { 'type' => 'RandomDecimal', 'digits' => 10 } + value = generator.call(hash) + expect(String(value).length).to eq 11 + end +end diff --git a/spec/lib/pact/provider/generator/random_hexadecimal_spec.rb b/spec/lib/pact/provider/generator/random_hexadecimal_spec.rb new file mode 100644 index 00000000..48bd6f94 --- /dev/null +++ b/spec/lib/pact/provider/generator/random_hexadecimal_spec.rb @@ -0,0 +1,25 @@ +require 'pact/provider/generator/random_hexadecimal' + +describe Pact::Provider::Generator::RandomHexadecimal do + generator = Pact::Provider::Generator::RandomHexadecimal.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomHexadecimal' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomHexadecimal' } + expect(generator.call(hash).length).to eq(8) + end + + it 'call with size' do + hash = { 'type' => 'RandomHexadecimal', 'digits' => 2 } + expect(generator.call(hash).length).to eq(2) + end +end diff --git a/spec/lib/pact/provider/generator/random_int_spec.rb b/spec/lib/pact/provider/generator/random_int_spec.rb new file mode 100644 index 00000000..e267c79b --- /dev/null +++ b/spec/lib/pact/provider/generator/random_int_spec.rb @@ -0,0 +1,25 @@ +require 'pact/provider/generator/random_int' + +describe Pact::Provider::Generator::RandomInt do + generator = Pact::Provider::Generator::RandomInt.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomInt' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomInt' } + expect(generator.call(hash).instance_of?(Integer)).to be true + end + + it 'call with min/max' do + hash = { 'type' => 'RandomInt', 'min' => 5, 'max' => 5 } + expect(generator.call(hash)).to eq 5 + end +end diff --git a/spec/lib/pact/provider/generator/random_string_spec.rb b/spec/lib/pact/provider/generator/random_string_spec.rb new file mode 100644 index 00000000..098563ec --- /dev/null +++ b/spec/lib/pact/provider/generator/random_string_spec.rb @@ -0,0 +1,25 @@ +require 'pact/provider/generator/random_string' + +describe Pact::Provider::Generator::RandomString do + generator = Pact::Provider::Generator::RandomString.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomString' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomString' } + expect(generator.call(hash).length).to eq(20) + end + + it 'call with size' do + hash = { 'type' => 'RandomString', 'size' => 30 } + expect(generator.call(hash).length).to eq(30) + end +end diff --git a/spec/lib/pact/provider/generator/regex_spec.rb b/spec/lib/pact/provider/generator/regex_spec.rb new file mode 100644 index 00000000..db2738a1 --- /dev/null +++ b/spec/lib/pact/provider/generator/regex_spec.rb @@ -0,0 +1,20 @@ +require 'pact/provider/generator/regex' + +describe Pact::Provider::Generator::Regex do + generator = Pact::Provider::Generator::Regex.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Regex' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Regex', 'pattern' => '(one|two)' } + expect(generator.call(hash)).to eq('one').or eq('two') + end +end diff --git a/spec/lib/pact/provider/generator/time_spec.rb b/spec/lib/pact/provider/generator/time_spec.rb new file mode 100644 index 00000000..9baa6b9b --- /dev/null +++ b/spec/lib/pact/provider/generator/time_spec.rb @@ -0,0 +1,20 @@ +require 'pact/provider/generator/time' + +describe Pact::Provider::Generator::Time do + generator = Pact::Provider::Generator::Time.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Time' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Time' } + expect(generator.call(hash).length).to eq(5) + end +end diff --git a/spec/lib/pact/provider/generator/uuid_spec.rb b/spec/lib/pact/provider/generator/uuid_spec.rb new file mode 100644 index 00000000..c19665bb --- /dev/null +++ b/spec/lib/pact/provider/generator/uuid_spec.rb @@ -0,0 +1,20 @@ +require 'pact/provider/generator/uuid' + +describe Pact::Provider::Generator::Uuid do + generator = Pact::Provider::Generator::Uuid.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Uuid' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Uuid' } + expect(generator.call(hash).length).to eq(36) + end +end diff --git a/spec/lib/pact/provider/generators_spec.rb b/spec/lib/pact/provider/generators_spec.rb new file mode 100644 index 00000000..198e1068 --- /dev/null +++ b/spec/lib/pact/provider/generators_spec.rb @@ -0,0 +1,124 @@ +require 'pact/provider/generators' +require 'pact/provider/request' + +describe Pact::Provider::Generators do + it 'execute_generators with Boolean' do + hash = { 'type' => 'Boolean' } + expect(Pact::Provider::Generators.execute_generators(hash)).to eq(true).or eq(false) + end + + it 'execute_generators with Date' do + hash = { 'type' => 'Date' } + expect(Pact::Provider::Generators.execute_generators(hash).length).to eq(10) + end + + it 'execute_generators with DateTime' do + hash = { 'type' => 'DateTime' } + expect(Pact::Provider::Generators.execute_generators(hash).length).to eq(16) + end + + it 'execute_generators with ProviderState' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + params = { 'access_token' => 'ABC' } + expect(Pact::Provider::Generators.execute_generators(hash, params)).to eq('Bearer ABC') + end + + it 'execute_generators with RandomDecimal' do + hash = { 'type' => 'RandomDecimal' } + expect(String(Pact::Provider::Generators.execute_generators(hash)).length).to eq(7) + end + + it 'execute_generators with RandomHexadecimal' do + hash = { 'type' => 'RandomHexadecimal' } + expect(Pact::Provider::Generators.execute_generators(hash).length).to eq(8) + end + + it 'execute_generators with RandomInt' do + hash = { 'type' => 'RandomInt' } + expect(Pact::Provider::Generators.execute_generators(hash).instance_of?(Integer)).to be true + end + + it 'execute_generators with RandomString' do + hash = { 'type' => 'RandomString' } + expect(Pact::Provider::Generators.execute_generators(hash).length).to eq(20) + end + + it 'execute_generators with Regex' do + hash = { 'type' => 'Regex', 'pattern' => '(one|two)' } + expect(Pact::Provider::Generators.execute_generators(hash)).to eq('one').or eq('two') + end + + it 'execute_generators with Time' do + hash = { 'type' => 'Time' } + expect(Pact::Provider::Generators.execute_generators(hash).length).to eq(5) + end + + it 'execute_generators with Uuid' do + hash = { 'type' => 'Uuid' } + expect(Pact::Provider::Generators.execute_generators(hash).length).to eq(36) + end + + it 'apply_generators for path' do + expected_request = Pact::Request::Expected.from_hash({ + method: 'GET', + path: '/path/1', + generators: { + 'path' => { + 'type' => 'ProviderState', + 'expression' => '/path/${itemID}' + } + } + }) + state_params = { + 'itemID' => 2 + } + request = Pact::Provider::Request::Replayable.new(expected_request, state_params) + expect(request.path).to eq('/path/2') + end + + it 'apply_generators for headers' do + expected_request = Pact::Request::Expected.from_hash({ + method: 'GET', + path: '/path/1', + headers: { + 'Authorization' => 'Bearer 123' + }, + generators: { + 'header' => { + '$.Authorization' => { + 'expression' => 'Bearer ${accessToken}', + 'type' => 'ProviderState' + } + } + } + }) + state_params = { + 'accessToken' => 'ABC' + } + request = Pact::Provider::Request::Replayable.new(expected_request, state_params) + expect(request.headers).to eq({ + 'HTTP_AUTHORIZATION' => 'Bearer ABC' + }) + end + + it 'apply_generators for body' do + expected_request = Pact::Request::Expected.from_hash({ + method: 'GET', + path: '/path/1', + body: { + 'result' => [ + '12345F' + ] + }, + generators: { + 'body' => { + '$.result[0]' => { + 'type' => 'RandomHexadecimal' + } + } + } + }) + request = Pact::Provider::Request::Replayable.new(expected_request) + expect(request.body['result'][0].length).to eq(8) + end +end