mockserver-client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+ require 'hashie'
3
+ require_relative './enum'
4
+
5
+ #
6
+ # A class to model the number of times an expectation should be respected.
7
+ # @author:: Nayyara Samuel (mailto: nayyara.samuel@opower.com)
8
+ #
9
+ module MockServer::Model
10
+ # Enum for boolean values since Ruby does not have this by default
11
+ class Boolean < Enum
12
+ def allowed_values
13
+ [true, false]
14
+ end
15
+ end
16
+
17
+ # Model for times class
18
+ class Times < Hashie::Dash
19
+ include Hashie::Extensions::MethodAccess
20
+ include Hashie::Extensions::IgnoreUndeclared
21
+ include Hashie::Extensions::Coercion
22
+
23
+ property :remaining_times, default: 0
24
+ property :unlimited, default: false
25
+
26
+ coerce_key :unlimited, Boolean
27
+ end
28
+
29
+ # DSL methods related to times
30
+ module DSL
31
+ def unlimited
32
+ Times.new(unlimited: true)
33
+ end
34
+
35
+ def once
36
+ Times.new(remaining_times: 1)
37
+ end
38
+
39
+ def exactly(num)
40
+ Times.new(remaining_times: num)
41
+ end
42
+
43
+ def at_least(num)
44
+ Times.new(remaining_times: num, unlimited: true)
45
+ end
46
+
47
+ def times(&_)
48
+ obj = once
49
+ yield obj if block_given?
50
+ obj
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: UTF-8
2
+ require_relative './abstract_client'
3
+
4
+ #
5
+ # The client used to interact with the proxy server.
6
+ # @author:: Nayyara Samuel (mailto: nayyara.samuel@opower.com)
7
+ #
8
+ class MockServer::ProxyClient < MockServer::AbstractClient
9
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ require 'active_support/inflector'
3
+ require 'json'
4
+
5
+ #
6
+ # A module that has common utility methods used by this project
7
+ # @author:: Nayyara Samuel (mailto: nayyara.samuel@opower.com)
8
+ #
9
+ module MockServer::UtilityMethods
10
+ # Does the following filter/transform operations on a hash
11
+ # - exclude null or empty valued keys from the hash
12
+ # - camelize the keys of the hash
13
+ # @param hash [Object] an object which will be used to create the hash. Must support :to_hash method
14
+ # @return [Hash] the transformed hash
15
+ def prepare_hash(obj)
16
+ obj = obj && obj.respond_to?(:to_hash) ? obj.to_hash : obj
17
+
18
+ if obj.is_a?(Hash)
19
+ obj.each_with_object({}) do |(k, v), acc|
20
+ is_empty = v.nil? || (v.respond_to?(:empty?) ? v.empty? : false)
21
+ acc[camelize(k)] = prepare_hash(v) unless is_empty
22
+ end
23
+ elsif obj.respond_to?(:map)
24
+ obj.map { |element| prepare_hash(element) }
25
+ else
26
+ obj
27
+ end
28
+ end
29
+
30
+ # @param [Object] an object to camelize the string representation of
31
+ # @return [String] the string converted to camelcase with first letter in lower case
32
+ def camelize(str)
33
+ str.to_s.camelize(:lower)
34
+ end
35
+
36
+ # Parse string response into JSON
37
+ # @param response [Response] from RestClient response
38
+ # @return [Hash] the parsed response or the object unmodified if parsing is not possible
39
+ def parse_response(response)
40
+ JSON.parse(response)
41
+ rescue JSON::ParserError
42
+ response
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: UTF-8
2
+ # Version for this gem
3
+ module MockServer
4
+ VERSION = '0.0.1'
5
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mockserver/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mockserver-client'
8
+ spec.version = MockServer::VERSION
9
+ spec.authors = ['Nayyara Samuel']
10
+ spec.email = ['nayyara.samuel@gmail.com']
11
+ spec.summary = %q(A Ruby client for MockServer)
12
+ spec.required_ruby_version = '~> 1.9.3'
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
17
+ spec.require_paths = ['lib']
18
+
19
+ spec.add_development_dependency 'bundler', '~> 1.6'
20
+ spec.add_development_dependency 'rake', '~> 10.3.2'
21
+ spec.add_development_dependency 'rspec', '~> 3.0.0'
22
+ spec.add_development_dependency 'simplecov', '~> 0.8.2'
23
+ spec.add_development_dependency 'webmock', '~> 1.18'
24
+ spec.add_development_dependency 'rubocop', '~> 0.23.0'
25
+
26
+ spec.add_dependency 'hashie', '~> 3.0'
27
+ spec.add_dependency 'json', '~> 1.8.1'
28
+ spec.add_dependency 'activesupport', '~> 4.1.1'
29
+ spec.add_dependency 'rest-client', '~> 1.6.7'
30
+ spec.add_dependency 'logging_factory', '~> 0.0.2'
31
+ end
@@ -0,0 +1,7 @@
1
+ {
2
+ "httpForward": {
3
+ "host": "www.mock-server.com",
4
+ "port": 80,
5
+ "scheme": "HTTP"
6
+ }
7
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "httpResponse": {
3
+ "statusCode": 401,
4
+ "headers": [
5
+ {
6
+ "name": "Content-Type",
7
+ "values": ["application/json; charset=utf-8"]
8
+ },
9
+ {
10
+ "name": "Cache-Control",
11
+ "values": ["public, max-age=86400"]
12
+ }
13
+ ],
14
+ "body": "incorrect username and password combination",
15
+ "delay": {
16
+ "timeUnit": "SECONDS",
17
+ "value": 1
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "httpRequest": {
3
+ "method": "POST",
4
+ "path": "/login",
5
+ "queryParameters": [
6
+ {
7
+ "name": "returnUrl",
8
+ "values": ["/account"]
9
+ }
10
+ ],
11
+ "cookies": [
12
+ {
13
+ "name": "sessionId",
14
+ "values": ["2By8LOhBmaW5nZXJwcmludCIlMDAzMW"]
15
+ }
16
+ ],
17
+ "body": {
18
+ "type": "EXACT",
19
+ "value": "{username:'foo', password:'bar'}"
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "httpRequest": {
3
+ "method": "POST",
4
+ "path": "/login",
5
+ "queryParameters": [
6
+ {
7
+ "values": [
8
+ "/account"
9
+ ],
10
+ "name": "returnUrl"
11
+ }
12
+ ],
13
+ "cookies": [
14
+ {
15
+ "values": [
16
+ "2By8LOhBmaW5nZXJwcmludCIlMDAzMW"
17
+ ],
18
+ "name": "sessionId"
19
+ }
20
+ ],
21
+ "body": {
22
+ "type": "EXACT",
23
+ "value": "{\"username\":\"foo\",\"password\":\"bar\"}"
24
+ }
25
+ },
26
+ "httpResponse": {
27
+ "statusCode": 401,
28
+ "headers": [
29
+ {
30
+ "values": [
31
+ "application/json; charset=utf-8"
32
+ ],
33
+ "name": "Content-Type"
34
+ },
35
+ {
36
+ "values": [
37
+ "public, max-age=86400"
38
+ ],
39
+ "name": "Cache-Control"
40
+ }
41
+ ],
42
+ "body": "{\"message\":\"incorrect username and password combination\"}",
43
+ "delay": {
44
+ "timeUnit": "SECONDS",
45
+ "value": 1
46
+ }
47
+ },
48
+ "times": {
49
+ "remainingTimes": 2,
50
+ "unlimited": false
51
+ }
52
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "httpRequest": {
3
+ "method": "POST",
4
+ "path": "/login"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "times": {
3
+ "remainingTimes": 1,
4
+ "unlimited": false
5
+ }
6
+ }
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+ require_relative '../spec_helper'
3
+
4
+ describe MockServer::Model::DSL do
5
+
6
+ it 'generates http requests correctly' do
7
+ mock_request = http_request(:POST, '/login')
8
+ mock_request.query_parameters = [parameter('returnUrl', '/account')]
9
+ mock_request.cookies = [cookie('sessionId', '2By8LOhBmaW5nZXJwcmludCIlMDAzMW')]
10
+ mock_request.body = exact("{username:'foo', password:'bar'}")
11
+
12
+ expect(to_camelized_hash(HTTP_REQUEST => mock_request)).to eq(FIXTURES.read('post_login_request.json'))
13
+
14
+ # Block style
15
+ mock_request = request(:POST, '/login') do |request|
16
+ request.query_parameters = [parameter('returnUrl', '/account')]
17
+ request.cookies = [cookie('sessionId', '2By8LOhBmaW5nZXJwcmludCIlMDAzMW')]
18
+ request.body = exact("{username:'foo', password:'bar'}")
19
+ end
20
+
21
+ expect(to_camelized_hash(HTTP_REQUEST => mock_request)).to eq(FIXTURES.read('post_login_request.json'))
22
+ end
23
+
24
+ it 'generates http responses correctly' do
25
+ mock_response = http_response
26
+ mock_response.status_code = 401
27
+ mock_response.headers = [header('Content-Type', 'application/json; charset=utf-8')]
28
+ mock_response.headers << header('Cache-Control', 'public, max-age=86400')
29
+ mock_response.body = body('incorrect username and password combination')
30
+ mock_response.delay = delay_by(:SECONDS, 1)
31
+
32
+ expect(to_camelized_hash(HTTP_RESPONSE => mock_response)).to eq(FIXTURES.read('incorrect_login_response.json'))
33
+
34
+ # Block style
35
+ mock_response = response do |response|
36
+ response.status_code = 401
37
+ response.headers = [header('Content-Type', 'application/json; charset=utf-8')]
38
+ response.headers << header('Cache-Control', 'public, max-age=86400')
39
+ response.body = body('incorrect username and password combination')
40
+ response.delay = delay_by(:SECONDS, 1)
41
+ end
42
+
43
+ expect(to_camelized_hash(HTTP_RESPONSE => mock_response)).to eq(FIXTURES.read('incorrect_login_response.json'))
44
+ end
45
+
46
+ it 'generates http forwards correctly' do
47
+ mock_forward = http_forward
48
+ mock_forward.host = 'www.mock-server.com'
49
+ mock_forward.port = 80
50
+
51
+ expect(to_camelized_hash(HTTP_FORWARD => mock_forward)).to eq(FIXTURES.read('forward_mockserver.json'))
52
+
53
+ # Block style
54
+ mock_forward = forward do |forward|
55
+ forward.host = 'www.mock-server.com'
56
+ forward.port = 80
57
+ end
58
+
59
+ expect(to_camelized_hash(HTTP_FORWARD => mock_forward)).to eq(FIXTURES.read('forward_mockserver.json'))
60
+ end
61
+
62
+ it 'generates times correctly' do
63
+ expect(to_camelized_hash(HTTP_TIMES => exactly(1))).to eq(FIXTURES.read('times_once.json'))
64
+
65
+ # Block style
66
+ mock_times = times do |times|
67
+ times.remaining_times = 1
68
+ end
69
+ expect(to_camelized_hash(HTTP_TIMES => mock_times)).to eq(FIXTURES.read('times_once.json'))
70
+ end
71
+
72
+ it 'generates body correctly' do
73
+ expect(to_camelized_hash(regex('*/login'))).to eq('type' => 'REGEX', 'value' => '*/login')
74
+ expect(to_camelized_hash(xpath('/login[1]'))).to eq('type' => 'XPATH', 'value' => '/login[1]')
75
+ expect(to_camelized_hash(parameterized(parameter('token', '4jy5hh')))).to eq('type' => 'PARAMETERS', 'parameters' => [{ 'name' => 'token', 'values' => ['4jy5hh'] }])
76
+ end
77
+
78
+ it 'generates times object correctly' do
79
+ expect(to_camelized_hash(unlimited)).to eq('unlimited' => 'true', 'remainingTimes' => 0)
80
+ expect(to_camelized_hash(at_least(2))).to eq('unlimited' => 'true', 'remainingTimes' => 2)
81
+ end
82
+
83
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+ require_relative '../spec_helper'
3
+
4
+ describe MockServer::MockServerClient do
5
+
6
+ let(:client) { MockServer::MockServerClient.new('localhost', 8080) }
7
+ let(:register_expectation_json) { FIXTURES.read('register_expectation.json').to_json }
8
+ let(:search_request_json) { FIXTURES.read('search_request.json').to_json }
9
+
10
+ before do
11
+ # To suppress logging output to standard output, write to a temporary file
12
+ client.logger = LoggingFactory::DEFAULT_FACTORY.log('test', output: 'tmp.log', truncate: true)
13
+
14
+ # Stub requests
15
+ stub_request(:put, /.+\/expectation/).with(body: register_expectation_json).to_return(status: 201)
16
+ stub_request(:put, /.+\/clear/).with(body: search_request_json).to_return(status: 202)
17
+ stub_request(:put, /.+\/reset/).to_return(status: 202)
18
+ stub_request(:put, /.+\/retrieve/).with(body: search_request_json).to_return(body: '', status: 200)
19
+ end
20
+
21
+ it 'registers an expectation correctly' do
22
+ mock_expectation = expectation do |expectation|
23
+ expectation.request do |request|
24
+ request.method = 'POST'
25
+ request.path = '/login'
26
+ request.query_parameters << parameter('returnUrl', '/account')
27
+ request.cookies << cookie('sessionId', '2By8LOhBmaW5nZXJwcmludCIlMDAzMW')
28
+ request.body = exact({ username: 'foo', password: 'bar' }.to_json)
29
+ end
30
+
31
+ expectation.response do |response|
32
+ response.status_code = 401
33
+ response.headers << header('Content-Type', 'application/json; charset=utf-8')
34
+ response.headers << header('Cache-Control', 'public, max-age=86400')
35
+ response.body = body({ message: 'incorrect username and password combination' }.to_json)
36
+ response.delay = delay_by(:SECONDS, 1)
37
+ end
38
+
39
+ expectation.times = exactly(2)
40
+ end
41
+
42
+ response = client.register(mock_expectation)
43
+ expect(response.code).to eq(201)
44
+ end
45
+
46
+ it 'raises an error when trying to set both forward and response' do
47
+ mock_expectation = expectation do |expectation|
48
+ expectation.request do |request|
49
+ request.method = 'POST'
50
+ request.path = '/login'
51
+ end
52
+
53
+ expectation.response do |response|
54
+ response.status_code = 401
55
+ end
56
+
57
+ expectation.forward do |forward|
58
+ forward.scheme = :HTTP
59
+ end
60
+ end
61
+
62
+ expect { client.register(mock_expectation) }.to raise_error(RuntimeError, 'You can only set either of ["httpResponse", "httpForward"]. But not both')
63
+ end
64
+
65
+ it 'clears requests from the mock server' do
66
+ expect(client.clear(request(:POST, '/login')).code).to eq(202)
67
+ end
68
+
69
+ it 'resets the mock server' do
70
+ expect(client.reset.code).to eq(202)
71
+ end
72
+
73
+ it 'retrieves requests correctly' do
74
+ expect(client.retrieve(request(:POST, '/login')).code).to eq(200)
75
+ end
76
+
77
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+ require_relative '../spec_helper'
3
+
4
+ describe MockServer::ProxyClient do
5
+
6
+ let(:client) { MockServer::ProxyClient.new('localhost', 8080) }
7
+ let(:register_expectation) { FIXTURES.read('register_expectation.json') }
8
+ let(:register_expectation_json) { register_expectation.to_json }
9
+ let(:search_request_json) { FIXTURES.read('search_request.json').to_json }
10
+
11
+ before do
12
+ # To suppress logging output to standard output, write to a temporary file
13
+ client.logger = LoggingFactory::DEFAULT_FACTORY.log('test', output: 'tmp.log', truncate: true)
14
+
15
+ # Stub requests
16
+ stub_request(:put, /.+\/retrieve/).with(body: search_request_json).to_return(
17
+ body: "[#{register_expectation_json}, #{register_expectation_json}]",
18
+ status: 200
19
+ )
20
+ stub_request(:put, /.+\/dumpToLog$/).to_return(status: 202).once
21
+ stub_request(:put, /.+\/dumpToLog\?type=java$/).to_return(status: 202).once
22
+ end
23
+
24
+ it 'verifies requests correctly' do
25
+ response = client.verify(request(:POST, '/login'), exactly(2))
26
+ expect(response).to eq([register_expectation, register_expectation])
27
+ end
28
+
29
+ it 'raises an error when verification fails' do
30
+ expect { client.verify(request(:POST, '/login')) }.to raise_error(RuntimeError, 'Expected request to be present: [1] (exactly). But found: [2]')
31
+ end
32
+
33
+ it 'dumps to logs correctly do' do
34
+ expect(client.dump_log.code).to eq(202)
35
+ expect(client.dump_log({}, true).code).to eq(202)
36
+ end
37
+ end