poisol 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4fcbeb995a43c675cf2210d7a48f603401bb2be8
4
+ data.tar.gz: b81a8125b1ff49b2aba7adbabe655df9ca45a078
5
+ SHA512:
6
+ metadata.gz: 24f67fabbfcc8a8d97e93c64f3f7656c823701c61d1c4eaaa8121733664afbf6cac12e90539788c04b6a980386a4b9ee7614bce9bb16d1f2769508be43f2cd3a
7
+ data.tar.gz: be0d4cfaf78a73a481407627500b83c47d1cffa0ec4fb1351cbd1bf7c47edebf35b6c9e3a48bdcafd85b346f92616145196358d47626a9ba87342b971396d110
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+
2
+ [![Build Status](https://travis-ci.org/paramadeep/poisol.svg?branch=master)](https://travis-ci.org/paramadeep/poisol) [![Dependency Status](https://gemnasium.com/paramadeep/poisol.svg)](https://gemnasium.com/paramadeep/poisol) [![Code Climate](https://codeclimate.com/github/paramadeep/poisol/badges/gpa.svg)](https://codeclimate.com/github/paramadeep/poisol) [![Coverage Status](https://coveralls.io/repos/paramadeep/poisol/badge.png)](https://coveralls.io/r/paramadeep/poisol)
3
+
4
+ #Poisol
5
+
6
+ For tests suite that uses stubs for http calls, Poisol generates builder objects that could be used to setup http stubs, similar to data builders used to set up test data in database.
7
+
8
+ Hence, avoiding clumsy manual json manipulations and duplications, and keeping test stub data setup as part of test's code.
9
+
10
+ ###Example
11
+
12
+ Stubbing a http service that provides user identification, gets as simple as
13
+
14
+ ```ruby
15
+ User.new.byName('Joe').hasRole('buyer').build
16
+ # => webmock that would return role as 'buyer' for http call user 'Joe'
17
+
18
+ User.new.byName('Mani').hasRole('Manager').build
19
+ # => webmock that would return role as 'Manager' for http call user 'Mani'
20
+
21
+ User.new.build
22
+ # => webmock that would return role as 'Singer' for http call user 'Raji'
23
+ ```
24
+ given a minimal configuration
25
+
26
+ ```yaml
27
+ #user.yml
28
+ url: http://authentication.service:80/user
29
+ query:
30
+ name: "Raji"
31
+ response_body:
32
+ '{
33
+ role: "singer"
34
+ }'
35
+ ```
36
+ Poisol, dynamically generates class called 'User', with methods 'byName' and 'hasRole', which can be used to build as many User's as we need for the tests.
37
+
38
+ The following can be dynamically configured
39
+ - Request
40
+ - url*
41
+ - type
42
+ - query params
43
+ - request body
44
+ - Response
45
+ - code*
46
+ - header*
47
+ - response body
48
+
49
+ ##ToDo
50
+ * Nested json
51
+ * Array json (column & row)
52
+ * Nested array json
53
+ * URL config
54
+ * Response code and header config
55
+ * Parent URL
56
+ * Documentation for 'getting started' and details
57
+ * Test coverage
58
+ * Throw error when configured and input field values are different
@@ -0,0 +1,12 @@
1
+ class ConfigMap
2
+ @@config_file_map = {}
3
+
4
+ def self.add map
5
+ @@config_file_map.update map
6
+ end
7
+
8
+ def self.file class_name
9
+ @@config_file_map[class_name]
10
+ end
11
+
12
+ end
@@ -0,0 +1,12 @@
1
+ class Domain
2
+ def self.load domain_config
3
+ base_hash = Parse.yaml_file domain_config
4
+ domain = base_hash["domain"]
5
+ port = base_hash["port"]
6
+ @@base_url = "#{domain.chomp('\\')}#{ port.present? ? ":#{port}" : "" }"
7
+ end
8
+
9
+ def self.base_url
10
+ @@base_url
11
+ end
12
+ end
@@ -0,0 +1,78 @@
1
+ class StubConfig
2
+ attr_reader :response,:request
3
+
4
+ def with_file file_name
5
+ @config_file = file_name
6
+ @config = Parse.yaml_file file_name
7
+ self
8
+ end
9
+
10
+ def is_inline
11
+ @is_inline = true
12
+ self
13
+ end
14
+
15
+ def is_exploded
16
+ @is_inline = false
17
+ self
18
+ end
19
+
20
+ def build
21
+ build_request
22
+ build_response
23
+ self
24
+ end
25
+
26
+ private
27
+ def build_request
28
+ @request = Request.new
29
+ @request.url = @config["request"]["url"]
30
+ @request.type = @config["request"]["type"].intern
31
+ @request.query = @config["request"]["query"]
32
+ @request.body = @is_inline? get_inline_request_body : get_exploaded_request_body
33
+ end
34
+
35
+ def build_response
36
+ @response = Response.new
37
+ response.body = @is_inline? get_inline_response_body : get_exploaded_response_body
38
+ handle_resonse_array_type
39
+ end
40
+
41
+ def handle_resonse_array_type
42
+ return if @config["response"].nil?
43
+ array_type = @config["response"]["array_type"]
44
+ @response.array_type = array_type.nil? ? "" : array_type
45
+ end
46
+
47
+
48
+ def get_inline_response_body
49
+ body = @config["response"]["body"]
50
+ return (body.nil?) ? "": (Parse.json_to_hash body)
51
+ end
52
+
53
+ def get_inline_request_body
54
+ body = @config["request"]["body"]
55
+ return (body.nil?) ? "": (Parse.json_to_hash body)
56
+ end
57
+
58
+ def get_exploaded_request_body
59
+ request_file = "#{File.dirname @config_file}/request.json"
60
+ return (File.exists? request_file) ? Parse.json_file_to_hash(request_file) : ""
61
+ end
62
+
63
+ def get_exploaded_response_body
64
+ response_file = "#{File.dirname @config_file}/response.json"
65
+ return (File.exists? response_file)? Parse.json_file_to_hash(response_file) : ""
66
+ end
67
+
68
+ end
69
+
70
+
71
+ class Request
72
+ attr_accessor :url,:type,:query,:body
73
+ end
74
+
75
+ class Response
76
+ attr_accessor :body,:array_type,:is_column_array,:is_row_array
77
+ end
78
+
@@ -0,0 +1,36 @@
1
+ class StubFactory
2
+ def build folder
3
+ folder.chomp! '/'
4
+ domain_config = Dir["#{folder}/domain.yml"].first
5
+ explolded_configs = Dir["#{folder}/**/config.yml"]
6
+ inline_configs = Dir["#{folder}/**/*.yml"] - ( (explolded_configs.nil?) ? [] : explolded_configs) - [domain_config]
7
+ Domain.load domain_config
8
+ generate_exploded_config explolded_configs unless explolded_configs.nil?
9
+ generate_inline_config inline_configs unless inline_configs.nil?
10
+ end
11
+
12
+ private
13
+
14
+
15
+ def generate_exploded_config explolded_configs
16
+ explolded_configs.each do |config_file|
17
+ dynamic_name = FileUtil.titilze_parent_dir config_file
18
+ config = StubConfig.new.is_exploded.with_file(config_file).build
19
+ create_class dynamic_name,config
20
+ end
21
+ end
22
+
23
+ def generate_inline_config inline_configs
24
+ inline_configs.each do |config_file|
25
+ dynamic_name = FileUtil.titilze_file_name config_file
26
+ config = StubConfig.new.is_inline.with_file(config_file).build
27
+ create_class dynamic_name,config
28
+ end
29
+ end
30
+
31
+ def create_class class_name,config
32
+ ConfigMap.add class_name => config
33
+ Object.const_set class_name,Class.new {include ClassTemplate}
34
+ end
35
+
36
+ end
@@ -0,0 +1,36 @@
1
+ module ClassTemplate
2
+
3
+ def initialize
4
+ @config = ConfigMap.file self.class.name
5
+ prepare_request
6
+ prepare_response
7
+ end
8
+
9
+ def prepare_request
10
+ prepare_request_url
11
+ prepare_request_query
12
+ prepare_request_body
13
+ end
14
+
15
+ def prepare_request_url
16
+ @url = @config.request.url
17
+ @type = @config.request.type
18
+ end
19
+
20
+ def prepare_request_query
21
+ @query = (@config.request.query.nil?) ? "" : generate_query_methods
22
+ end
23
+
24
+ def prepare_request_body
25
+ @request_body = @config.request.body == "" ? "" : generate_request_methods
26
+ end
27
+
28
+ def build
29
+ stub = stub_request(@type, "http://#{Domain.base_url}/#{@url}")
30
+ stub.with(:query => @query) unless @query.eql? ""
31
+ stub.with(:body => @request_body) unless @request_body.eql? ""
32
+ @response_body = Parse.hash_array_to_column_hash(@response_body) if @config.response.array_type == "column_array"
33
+ stub.to_return(:status => 200, :body => @response_body, :headers => {})
34
+ end
35
+
36
+ end
@@ -0,0 +1,11 @@
1
+ module ClassTemplate
2
+ def generate_query_methods
3
+ @query = @config.request.query
4
+ @query.each do |field|
5
+ define_singleton_method("by#{field[0].capitalize}") do |*value|
6
+ @query[field[0]] = value[0]
7
+ self
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module ClassTemplate
2
+ def generate_request_methods
3
+ @request_body = @config.request.body
4
+ return if @request_body.nil?
5
+ @request_body.each do |field|
6
+ define_singleton_method("by_#{field[0].underscore}") do |*value|
7
+ @request_body[field[0]] = value[0]
8
+ self
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,49 @@
1
+ module ClassTemplate
2
+
3
+ def prepare_response
4
+ return if @config.response.body.blank?
5
+ @config.response.array_type.blank? ? generate_methods_to_alter_response_object : generate_methods_to_alter_response_array
6
+ end
7
+
8
+ def generate_methods_to_alter_response_array
9
+ @response_body_object = @config.response.body
10
+ @response_body = []
11
+ generate_method_to_append_response_array
12
+ generate_method_to_alter_response_array_object
13
+ end
14
+
15
+ def generate_method_to_alter_response_array_object
16
+ @response_body_object.each do |field|
17
+ field_name = field[0]
18
+ actual_field_value = field[1]
19
+ define_singleton_method("with_#{field_name.underscore}") do |*input_value|
20
+ input_value = input_value[0]
21
+ @response_body.last[field_name] = actual_field_value.class.to_s == "Hash" ? @response_body.last[field_name].deep_merge(input_value) : input_value
22
+ self
23
+ end
24
+ end
25
+ end
26
+
27
+ def generate_method_to_append_response_array
28
+ object_name = self.class.to_s.classify.underscore
29
+ method_name = "has_#{object_name}"
30
+ define_singleton_method(method_name) do
31
+ @response_body << @response_body_object.deep_dup
32
+ self
33
+ end
34
+ end
35
+
36
+ def generate_methods_to_alter_response_object
37
+ @response_body = @config.response.body
38
+ @response_body.each do |field|
39
+ field_name = field[0]
40
+ actual_field_value = field[1]
41
+ define_singleton_method("has_#{field_name.underscore}") do |*input_value|
42
+ input_value = input_value[0]
43
+ @response_body[field_name] = actual_field_value.class.to_s == "Hash" ? @response_body[field_name].deep_merge(input_value) : input_value
44
+ self
45
+ end
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,18 @@
1
+ class FileUtil
2
+
3
+ def self.titilze_parent_dir file_name
4
+ titilize File.basename(File.dirname file_name)
5
+ end
6
+
7
+ def self.titilze_file_name file_name
8
+ titilize ((File.basename file_name).chomp ".yml")
9
+ end
10
+
11
+ private
12
+
13
+ def self.titilize input
14
+ (input).capitalize.split('_').reduce{|c,a| c+a.capitalize}
15
+ end
16
+
17
+ end
18
+
@@ -0,0 +1,25 @@
1
+ class Parse
2
+
3
+ def self.json_file_to_hash file_name
4
+ JSON.parse File.read(file_name)
5
+ end
6
+
7
+ def self.yaml_file file_name
8
+ YAML.load_file(file_name)
9
+ end
10
+
11
+ def self.json_to_hash json
12
+ JSON.parse json
13
+ end
14
+
15
+ def self.hash_array_to_column_hash hash_array
16
+ column_hash = Hash.new
17
+ hash_array[0].each_key { |key| column_hash.merge!(key=>[])}
18
+ hash_array.each do |hash|
19
+ column_hash.each_key {|key| column_hash[key].append hash[key]}
20
+ end
21
+ return column_hash
22
+ end
23
+
24
+ end
25
+
data/lib/poisol.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'active_support/all'
2
+ Dir["#{File.dirname(__FILE__)}/poisol/**/*.rb"].each { |f| require(f) }
@@ -0,0 +1,15 @@
1
+ describe ClassTemplate, "#array" do
2
+
3
+ it "column array" do
4
+ Columns.new.has_column.has_column.with_title("abc").with_category("12").build
5
+ response = RestClient.get "http://localhost:80/column"
6
+ expect(response.body).to eq({"title"=>["independance", "abc"], "category"=>["10","12"]})
7
+ end
8
+
9
+ it "row array" do
10
+ Rows.new.has_row.has_row.with_title("abc").with_category("age_group" => "12").build
11
+ response = RestClient.get "http://localhost:80/row"
12
+ expect(response.body).to eq([{"title"=>"independance", "category"=>{"age_group"=>"10"}}, {"title"=>"abc", "category"=>{"age_group"=>"12"}}])
13
+ end
14
+
15
+ end
@@ -0,0 +1,16 @@
1
+ describe ClassTemplate, "#get_books" do
2
+
3
+ it "default request and response" do
4
+ Book.new.build()
5
+ response = RestClient.get "http://localhost:80/book",{:params => {:author=>'bharathi'}}
6
+ expect(response.body).to eq("title"=>"independance", "category"=>{"age_group"=>"10", "genre"=>"action", "publisher"=>{"name"=>"summa", "place"=>"erode"}})
7
+ end
8
+
9
+ it "dynamic response" do
10
+ Book.new.has_category({"age_group"=>"11", "publisher"=>{"name"=>"oxford"}}).build()
11
+ response = RestClient.get "http://localhost:80/book",{:params => {:author=>'bharathi'}}
12
+ expect(response.body).to eq("title"=>"independance", "category"=>{"age_group"=>"11", "genre"=>"action", "publisher"=>{"name"=>"oxford", "place"=>"erode"}})
13
+ end
14
+
15
+ end
16
+
@@ -0,0 +1,18 @@
1
+ describe ClassTemplate, "#post_user" do
2
+
3
+ it "default request and response" do
4
+ User.new.build()
5
+ response = RestClient.post "http://localhost:80/users","name"=>"deepak"
6
+ expect(response.body).to eq("job"=>'sleeping_bag')
7
+ end
8
+
9
+ it "dynamic request and response" do
10
+ name = "ummy"
11
+ job = "vetti"
12
+ User.new.by_name(name).has_job(job).build()
13
+ response = RestClient.post "http://localhost:80/users","name"=>name
14
+ expect(response.body).to eq("job"=>job)
15
+ end
16
+
17
+ end
18
+
@@ -0,0 +1,28 @@
1
+ require "rspec/expectations"
2
+ require 'rest_client'
3
+ require 'webmock'
4
+ include WebMock::API
5
+
6
+ require_relative '../lib/poisol'
7
+ require 'pry'
8
+
9
+ require 'simplecov'
10
+ SimpleCov.minimum_coverage 40
11
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
12
+ SimpleCov::Formatter::HTMLFormatter
13
+ ]
14
+ SimpleCov.start
15
+
16
+ RSpec.configure do |config|
17
+
18
+ config.before(:each) do
19
+ WebMock.reset!
20
+ end
21
+
22
+ config.before(:suite) do
23
+ WebMock.disable_net_connect!(:allow_localhost => true)
24
+ factory = StubFactory.new.build("data")
25
+ end
26
+
27
+ end
28
+
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poisol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Deepak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.1.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 10.3.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 10.3.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.10.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.10.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubygems-tasks
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.4
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.9.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.9.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.18.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.18.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rest-client
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.7.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.7.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: activesupport
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 4.1.6
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 4.1.6
125
+ description: Data builders for http stubs
126
+ email:
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - README.md
132
+ - lib/poisol.rb
133
+ - lib/poisol/config_map.rb
134
+ - lib/poisol/domain.rb
135
+ - lib/poisol/stub_config.rb
136
+ - lib/poisol/stub_factory.rb
137
+ - lib/poisol/template/class_template.rb
138
+ - lib/poisol/template/query_handler.rb
139
+ - lib/poisol/template/request_handler.rb
140
+ - lib/poisol/template/response_handler.rb
141
+ - lib/poisol/utils/file_util.rb
142
+ - lib/poisol/utils/parse.rb
143
+ - spec/class_template/array_spec.rb
144
+ - spec/class_template/get_spec.rb
145
+ - spec/class_template/post_spec.rb
146
+ - spec/spec_helper.rb
147
+ homepage: https://github.com/paramadeep/poisol
148
+ licenses:
149
+ - MIT
150
+ metadata: {}
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.2.2
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Data builders for http stubs
171
+ test_files:
172
+ - spec/spec_helper.rb
173
+ - spec/class_template/post_spec.rb
174
+ - spec/class_template/get_spec.rb
175
+ - spec/class_template/array_spec.rb