-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(stub): add pact-stub-service CLI
Allow existing pact files to be used to create a stub service
- Loading branch information
Showing
7 changed files
with
265 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env ruby | ||
require 'pact/stub_service/cli' | ||
Pact::StubService::CLI.start |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
require 'thor' | ||
|
||
module Pact | ||
module MockService | ||
class CLI < Thor | ||
## | ||
# Custom Thor task allows the following: | ||
# | ||
# `script arg1 arg2` to be interpreted as `script <default_task> arg1 arg2` | ||
# `--option 1 --option 2` to be interpreted as `--option 1 2` (the standard Thor format for multiple value options) | ||
# `script --help` to display the help for the default task instead of the command list | ||
# | ||
class CustomThor < ::Thor | ||
|
||
no_commands do | ||
def self.start given_args = ARGV, config = {} | ||
super(massage_args(given_args)) | ||
end | ||
|
||
def help *args | ||
if args.empty? | ||
super(self.class.default_task) | ||
else | ||
super | ||
end | ||
end | ||
|
||
def self.massage_args argv | ||
prepend_default_task_name(turn_muliple_tag_options_into_array(argv)) | ||
end | ||
|
||
def self.prepend_default_task_name argv | ||
if known_first_arguments.include?(argv[0]) | ||
argv | ||
else | ||
[default_command] + argv | ||
end | ||
end | ||
|
||
# other task names, help, and the help shortcuts | ||
def self.known_first_arguments | ||
@known_first_arguments ||= tasks.keys + ::Thor::HELP_MAPPINGS + ['help'] | ||
end | ||
|
||
def self.turn_muliple_tag_options_into_array argv | ||
new_argv = [] | ||
opt_name = nil | ||
argv.each_with_index do | arg, i | | ||
if arg.start_with?('-') | ||
opt_name = arg | ||
existing = new_argv.find { | a | a.first == opt_name } | ||
if !existing | ||
new_argv << [arg] | ||
end | ||
else | ||
if opt_name | ||
existing = new_argv.find { | a | a.first == opt_name } | ||
existing << arg | ||
opt_name = nil | ||
else | ||
new_argv << [arg] | ||
end | ||
end | ||
end | ||
new_argv.flatten | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
require 'pact/mock_service/cli/custom_thor' | ||
require 'webrick/https' | ||
require 'rack/handler/webrick' | ||
require 'fileutils' | ||
require 'pact/mock_service/server/wait_for_server_up' | ||
require 'pact/mock_service/cli/pidfile' | ||
require 'socket' | ||
|
||
module Pact | ||
module StubService | ||
class CLI < Pact::MockService::CLI::CustomThor | ||
|
||
desc 'PACT ...', "Start a stub service with the given pact file(s). Note that this is in beta release, and no logic has been added to handle the situation where more than one matching interaction is found for a request. At the moment, an error response will be returned." | ||
|
||
method_option :port, aliases: "-p", desc: "Port on which to run the service" | ||
method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost' | ||
method_option :log, aliases: "-l", desc: "File to which to log output" | ||
method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses" | ||
method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false | ||
method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS" | ||
method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS" | ||
method_option :stub_pactfile_paths, hide: true | ||
|
||
def service(*pactfiles) | ||
raise Thor::Error.new("Please provide an existing pact file to load") if pactfiles.empty? | ||
require 'pact/mock_service/run' | ||
options.stub_pactfile_paths = pactfiles | ||
opts = Thor::CoreExt::HashWithIndifferentAccess.new | ||
opts.merge!(options) | ||
opts[:stub_pactfile_paths] = pactfiles | ||
opts[:pactfile_write_mode] = 'none' | ||
MockService::Run.(opts) | ||
end | ||
|
||
desc 'version', "Show the pact-stub-service gem version" | ||
|
||
def version | ||
require 'pact/mock_service/version.rb' | ||
puts Pact::MockService::VERSION | ||
end | ||
|
||
default_task :service | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#!/usr/bin/env bash | ||
|
||
# BEFORE SUITE start mock service | ||
# invoked by the pact framework | ||
bundle exec bin/pact-stub-service tmp/pacts/foo-bar.json \ | ||
--port 1234 \ | ||
--log ./tmp/bar_stub_service.log & | ||
pid=$! | ||
|
||
# BEFORE SUITE wait for mock service to start up | ||
# invoked by the pact framework | ||
while [ "200" -ne "$(curl -H "X-Pact-Mock-Service: true" -s -o /dev/null -w "%{http_code}" localhost:1234)" ]; do sleep 0.5; done | ||
|
||
# IN A TEST execute interaction(s) | ||
# this would be done by the consumer code under test | ||
curl localhost:1234/foo | ||
echo '' | ||
|
||
|
||
# AFTER SUITE stop mock service | ||
# this would be invoked by the test framework | ||
kill -2 $pid | ||
|
||
while [ kill -0 $pid 2> /dev/null ]; do sleep 0.5; done | ||
|
||
echo '' | ||
echo 'FYI the stub service logs are:' | ||
cat ./tmp/bar_stub_service.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
require 'pact/mock_service/cli/custom_thor' | ||
|
||
class Pact::MockService::CLI | ||
|
||
class Delegate | ||
def self.call options; end | ||
end | ||
|
||
class TestThor < CustomThor | ||
desc 'ARGUMENT', 'This is the description' | ||
def test_default(argument) | ||
Delegate.call(argument: argument) | ||
end | ||
|
||
desc '', '' | ||
method_option :multi, type: :array | ||
def test_multiple_options | ||
Delegate.call(options) | ||
end | ||
|
||
default_command :test_default | ||
end | ||
|
||
describe CustomThor do | ||
subject { TestThor.new } | ||
|
||
it "invokes the default task when aguments are given without specifying a task" do | ||
expect(Delegate).to receive(:call).with(argument: 'foo') | ||
TestThor.start(%w{foo}) | ||
end | ||
|
||
it "converts options that are specified multiple times into a single array" do | ||
expect(Delegate).to receive(:call).with({'multi' => ['one', 'two']}) | ||
TestThor.start(%w{test_multiple_options --multi one --multi two}) | ||
end | ||
|
||
describe ".prepend_default_task_name" do | ||
let(:argv_with) { [TestThor.default_command, 'foo'] } | ||
|
||
context "when the default task name is given" do | ||
it "does not prepend the default task name" do | ||
expect(TestThor.prepend_default_task_name(argv_with)).to eq(argv_with) | ||
end | ||
end | ||
|
||
context "when the first argument is --help" do | ||
let(:argv) { ['--help', 'foo'] } | ||
|
||
it "does not prepend the default task name" do | ||
expect(TestThor.prepend_default_task_name(argv)).to eq(argv) | ||
end | ||
end | ||
|
||
context "when the default task name is not given" do | ||
let(:argv) { ['foo'] } | ||
|
||
it "prepends the default task name" do | ||
expect(TestThor.prepend_default_task_name(argv)).to eq(argv_with) | ||
end | ||
end | ||
end | ||
|
||
describe ".turn_muliple_tag_options_into_array" do | ||
it "turns '--tag foo --tag bar' into '--tag foo bar'" do | ||
input = %w{--ignore this --tag foo --tag bar --wiffle --that} | ||
output = %w{--ignore this --tag foo bar --wiffle --that } | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output | ||
end | ||
|
||
it "turns '--tag foo bar --tag meep' into '--tag foo meep bar'" do | ||
input = %w{--ignore this --tag foo bar --tag meep --wiffle --that} | ||
output = %w{--ignore this --tag foo meep bar --wiffle --that} | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output | ||
end | ||
|
||
it "turns '--tag foo --tag bar wiffle' into '--tag foo bar wiffle' which is silly" do | ||
input = %w{--ignore this --tag foo --tag bar wiffle} | ||
output = %w{--ignore this --tag foo bar wiffle} | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output | ||
end | ||
|
||
it "maintains '--tag foo bar wiffle'" do | ||
input = %w{--ignore this --tag foo bar wiffle --meep} | ||
output = %w{--ignore this --tag foo bar wiffle --meep} | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output | ||
end | ||
|
||
it "turns '-t foo -t bar' into '-t foo bar'" do | ||
input = %w{--ignore this -t foo -t bar --meep --that 1 2 3} | ||
output = %w{--ignore this -t foo bar --meep --that 1 2 3} | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output | ||
end | ||
|
||
it "doesn't change anything when there are no duplicate options" do | ||
input = %w{--ignore this --taggy foo --blah bar --wiffle --that} | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq input | ||
end | ||
|
||
it "return an empty array when given an empty array" do | ||
input = [] | ||
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq input | ||
end | ||
end | ||
end | ||
end |