Skip to content

Commit

Permalink
Merge pull request #9 from julianghionoiu/update-client
Browse files Browse the repository at this point in the history
Update client
  • Loading branch information
julianghionoiu committed Feb 1, 2018
2 parents 72481a3 + e5d9444 commit 0eb347b
Show file tree
Hide file tree
Showing 40 changed files with 1,085 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@ Gemfile.lock
out
coverage
.DS_Store
challenges
3 changes: 3 additions & 0 deletions .gitmodules
Expand Up @@ -4,3 +4,6 @@
[submodule "features/spec"]
path = features/spec
url = git@github.com:julianghionoiu/tdl-client-spec.git
[submodule "wiremock"]
path = wiremock
url = git@github.com:julianghionoiu/tdl-client-test-wiremock.git
14 changes: 11 additions & 3 deletions README.md
Expand Up @@ -26,11 +26,19 @@ All test require the ActiveMQ broker to be started.
The following commands are available for the broker.

```
./broker/activemq-wrapper start
./broker/activemq-wrapper console
./broker/activemq-wrapper stop
python ./broker/activemq-wrapper.py start
python wiremock/wiremock-wrapper.py start 41375
python wiremock/wiremock-wrapper.py start 8222
```

Run tests with `rake features`.
To run a single scenario execute `cucumber path/to/file.feature:line_no`
Recommendation is to use the cucumber command instead of rake always outside of CI.

# Cleanup

Stop external dependencies
```
python ./broker/activemq-wrapper.py stop
```

2 changes: 1 addition & 1 deletion broker
33 changes: 26 additions & 7 deletions features/step_definitions.rb → features/queue_steps.rb
Expand Up @@ -29,11 +29,24 @@
@response_queue = BROKER.add_queue("#{unique_id}.resp")
@response_queue.purge

@client = TDL::Client.new(hostname: HOSTNAME, port: STOMP_PORT, unique_id: unique_id)
config = TDL::ImplementationRunnerConfig.new()
.set_hostname(HOSTNAME)
.set_port(STOMP_PORT)
.set_unique_id(unique_id)

@queueBasedImplementationRunnerBuilder = TDL::QueueBasedImplementationRunnerBuilder.new()
.set_config(config)
@queueBasedImplementationRunner = @queueBasedImplementationRunnerBuilder.create
end

Given(/^the broker is not available$/) do
@client = TDL::Client.new(hostname: '111', port: STOMP_PORT, unique_id: 'broker')
config = TDL::ImplementationRunnerConfig.new()
.set_hostname('111')
.set_port(STOMP_PORT)
.set_unique_id('X')

@queueBasedImplementationRunnerBuilder = TDL::QueueBasedImplementationRunnerBuilder.new()
.set_config(config);
end

Given(/^I receive 50 identical requests like:$/) do |table|
Expand All @@ -47,7 +60,7 @@


Then(/^the time to wait for requests is (\d+)ms$/) do |expected_timeout|
assert_equal expected_timeout.to_i, @client.get_request_timeout_millis,
assert_equal expected_timeout.to_i, @queueBasedImplementationRunner.get_request_timeout_millis,
'The client request timeout has a different value.'
end

Expand All @@ -64,7 +77,7 @@
end

Then(/^the processing time should be lower than (\d+)ms$/) do |expected_value|
assert expected_value.to_i > @client.total_processing_time,
assert expected_value.to_i > @queueBasedImplementationRunner.total_processing_time,
'Request queue has a different value.'
end

Expand Down Expand Up @@ -115,11 +128,17 @@ def as_action(actionName)
processing_rules = TDL::ProcessingRules.new

table.hashes.each do |row|
processing_rules.on(row[:method]).call(as_implementation(row[:call])).then(as_action(row[:action]))
@queueBasedImplementationRunnerBuilder
.with_solution_for(
row[:method],
as_implementation(row[:call]),
as_action(row[:action]))
end


@queueBasedImplementationRunner = @queueBasedImplementationRunnerBuilder.create

@captured_io = capture_subprocess_io do
@client.go_live_with(processing_rules)
@queueBasedImplementationRunner.run
end
@captured_io.each { |x| puts x }
end
Expand Down
12 changes: 12 additions & 0 deletions features/runner/noisy_implementation_runner.rb
@@ -0,0 +1,12 @@
class NoisyImplementationRunner

def initialize(deploy_message, audit_stream)
@deploy_message = deploy_message
@audit_stream = audit_stream
end

def run
@audit_stream.write_line(@deploy_message)
end

end
5 changes: 5 additions & 0 deletions features/runner/quiet_implementation_runner.rb
@@ -0,0 +1,5 @@
class QuietImplementationRunner
def run
# Do nothing.
end
end
18 changes: 18 additions & 0 deletions features/runner/test_audit_stream.rb
@@ -0,0 +1,18 @@
class TestAuditStream
def initialize
@total = ''
end

def write_line(s)
@total += "#{s}\n"
end

def get_log
puts @total
@total
end

def clear
@total = ''
end
end
61 changes: 61 additions & 0 deletions features/runner/wiremock_process.rb
@@ -0,0 +1,61 @@
require 'unirest'

class WiremockProcess

def initialize(hostname, port)
@base_url = "http://#{hostname}:#{port}"
end

def create_new_mapping(config)
request_json = {
request: {
urlPattern: config[:endpointMatches],
url: config[:endpointEquals],
method: config[:verb]
},
response: {
body: config[:responseBody],
statusMessage: config[:statusMessage],
status: config[:status]
}
}

if config[:acceptHeader]
request_json[:request][:headers] = {
accept: {
contains: config[:acceptHeader]
}
}
end

response = Unirest.post "#{@base_url}/__admin/mappings/new",
headers: {"Accept" => "application/json"},
parameters: request_json.to_json
end

def reset
Unirest.post "#{@base_url}/__admin/reset"
end

def verify_endpoint_was_hit(endpoint, method_type, body)
count_requests_with_endpoint(endpoint, method_type, body) === 1
end

def count_requests_with_endpoint(endpoint, verb, body)
request_json = {
url: endpoint,
method: verb
}

if body
request_json[:bodyPatterns] = [{equalTo: body}]
end

response = Unirest.post "#{@base_url}/__admin/requests/count",
headers: {"Accept" => "application/json"},
parameters: request_json.to_json

response.body["count"]
end

end
134 changes: 134 additions & 0 deletions features/runner_steps.rb
@@ -0,0 +1,134 @@
require 'fileutils'

require_relative './runner/wiremock_process'
require_relative './runner/test_audit_stream'
require_relative './runner/noisy_implementation_runner'
require_relative './runner/quiet_implementation_runner'

audit_stream = TestAuditStream.new
implementation_runner = QuietImplementationRunner.new
working_directory = './'

Given(/^There is a challenge server running on "([^"]*)" port (\d+)$/) do |hostname, port|
@challenge_hostname = hostname
@port = port

@challenge_server_stub = WiremockProcess.new(hostname, port)
@challenge_server_stub.reset
end

Given(/^There is a recording server running on "([^"]*)" port (\d+)$/) do |hostname, port|
@recording_server_stub = WiremockProcess.new(hostname, port)
@recording_server_stub.reset
end

Given(/^the challenge server exposes the following endpoints$/) do |table|
table.hashes.each do |config|
@challenge_server_stub.create_new_mapping(config)
end
end

Given(/^the recording server exposes the following endpoints$/) do |table|
table.hashes.each do |config|
@recording_server_stub.create_new_mapping(config)
end
end

Given(/^the challenge server returns (\d+) for all requests$/) do |return_code|
#HACK to get the unirest ruby client to NOT follow the redirect
(return_code.to_i.equal? 301) ? _return_code = 306 : _return_code = return_code

puts ">>>>>>>>>#{_return_code},#{return_code}"
@challenge_server_stub.create_new_mapping({
endpointMatches: '^(.*)',
status: _return_code,
verb: 'ANY'
})
end

Given(/^the challenge server returns (\d+), response body "([^"]*)" for all requests$/) do |return_code, body|
@challenge_server_stub.create_new_mapping({
endpointMatches: '^(.*)',
status: return_code,
verb: 'ANY',
responseBody: body
})
end

Given(/^the challenges folder is empty$/) do
FileUtils.rm_rf(Dir.glob('challenges/*'))
end

Given(/^the action input comes from a provider returning "([^"]*)"$/) do |s|
@action_provider_callback = ->() {s}
end

Given(/^there is an implementation runner that prints "([^"]*)"$/) do |s|
@implementation_runner_message = s
implementation_runner = NoisyImplementationRunner.new(s, audit_stream)
end

Given(/^recording server is returning error/) do
@recording_server_stub.reset
end

Given(/^journeyId is "([^"]*)"$/) do |journey_id|
@journey_id = journey_id
end

Given(/^the challenge server is broken$/) do
@challenge_server_stub.reset
end

When(/^user starts client$/) do
audit_stream.clear

config = TDL::ChallengeSessionConfig.for_journey_id(@journey_id)
.with_server_hostname(@challenge_hostname)
.with_port(@port)
.with_colours(true)
.with_audit_stream(audit_stream)
.with_recording_system_should_be_on(true)
.with_working_directory(working_directory)

TDL::ChallengeSession.for_runner(implementation_runner)
.with_config(config)
.with_action_provider(@action_provider_callback)
.start
end

Then(/^the server interaction should contain the following lines:$/) do |expected_output|
total = audit_stream.get_log.strip
lines = expected_output.split("\n")
lines.each do |line|
line = line.strip
unless line.empty?
assert total.include?(line), 'Expected string is not contained in output'
end
end
end

Then(/^the server interaction should look like:$$/) do |expected_output|
total = audit_stream.get_log.strip
assert_equal total, expected_output.strip.gsub(/\r/,''), 'Expected string is not contained in output'
end

Then(/^the recording system should be notified with "([^"]*)"$/) do |expected_output|
audit_stream.get_log
assert @recording_server_stub.verify_endpoint_was_hit('/notify', 'POST', expected_output)
end

Then(/^the file "([^"]*)" should contain$/) do |file, text|
content = File.read(file)
assert_equal content.strip, text.strip.gsub(/\r/,''), 'Contents of the file is not what is expected'
end

Then(/^the implementation runner should be run with the provided implementations$/) do
total = audit_stream.get_log
assert total.include?(@implementation_runner_message)
end

Then(/^the client should not ask the user for input$/) do
total = audit_stream.get_log
assert !total.include?('Selected action is:')
end
2 changes: 1 addition & 1 deletion features/spec

0 comments on commit 0eb347b

Please sign in to comment.