scenario_server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,283 @@
1
+ #!/usr/env ruby
2
+ require 'fileutils'
3
+ require 'sequel'
4
+ require 'sequel/extensions/pretty_table'
5
+
6
+ class ScenarioDB
7
+
8
+ attr_accessor :db, :db_file, :scenarios, :routes, :testdata
9
+
10
+ def initialize(options={})
11
+ if options[:db_file]
12
+ self.db_file = options[:db_file]
13
+ else
14
+ self.db_file = File.dirname(File.expand_path(__FILE__)) + '/data/scenario_db.sqlite3'
15
+ end
16
+
17
+ handle_cli_options(options)
18
+ end
19
+
20
+ def handle_cli_options(options)
21
+ if options[:setup]
22
+
23
+ configure_database
24
+ puts 'database setup complete.'
25
+ end
26
+
27
+ if !options[:add_scenario].nil? && options[:add_scenario].length == 1
28
+ configure_database
29
+
30
+ add_scenario(options[:add_scenario][0])
31
+ if self.scenarios.count > 0
32
+ Sequel::PrettyTable.print(self.scenarios)
33
+ else
34
+ puts 'No records to display.'
35
+ end
36
+ end
37
+
38
+ if !options[:delete_scenario].nil?
39
+ configure_database
40
+
41
+ delete_scenario(options[:delete_scenario])
42
+ if self.db[:scenarios].count > 0
43
+ Sequel::PrettyTable.print(self.db[:scenarios])
44
+ else
45
+ puts 'No records to display.'
46
+ end
47
+ end
48
+
49
+ if !options[:add_route].nil? && options[:add_route].length == 4
50
+ configure_database
51
+
52
+ add_route_for_scenario(options[:add_route][0], options[:add_route][1], options[:add_route][2], options[:add_route][3])
53
+ if self.routes.count > 0
54
+ Sequel::PrettyTable.print(self.routes)
55
+ else
56
+ puts 'No records to display.'
57
+ end
58
+ end
59
+
60
+ if !options[:delete_route].nil?
61
+ configure_database
62
+
63
+ delete_route(options[:delete_route])
64
+ if self.db[:routes].count > 0
65
+ Sequel::PrettyTable.print(self.routes)
66
+ else
67
+ puts 'No records to display.'
68
+ end
69
+ end
70
+
71
+ if !options[:add_testdata].nil? && options[:add_testdata].length == 3
72
+ configure_database
73
+
74
+ add_testdata_for_scenario(options[:add_testdata][0], options[:add_testdata][1], options[:add_testdata][2])
75
+ if self.testdata.count > 0
76
+ Sequel::PrettyTable.print(self.testdata)
77
+ else
78
+ puts 'No records to display.'
79
+ end
80
+ end
81
+
82
+ if !options[:delete_testdata].nil?
83
+ configure_database
84
+
85
+ delete_route(options[:delete_testdata])
86
+ if self.testdata.count > 0
87
+ Sequel::PrettyTable.print(self.testdata)
88
+ else
89
+ puts 'No records to display.'
90
+ end
91
+ end
92
+
93
+ if options[:scenarios]
94
+ configure_database
95
+
96
+ if self.scenarios.count > 0
97
+ Sequel::PrettyTable.print(self.scenarios)
98
+ else
99
+ puts 'No records to display.'
100
+ end
101
+ end
102
+
103
+ if options[:routes]
104
+ configure_database
105
+
106
+ if self.routes.count > 0
107
+ Sequel::PrettyTable.print(self.routes)
108
+ else
109
+ puts 'No records to display.'
110
+ end
111
+ end
112
+
113
+ if options[:testdata]
114
+ configure_database
115
+
116
+ if self.testdata.count > 0
117
+ Sequel::PrettyTable.print(self.testdata)
118
+ else
119
+ puts 'No records to display.'
120
+ end
121
+ end
122
+ end
123
+
124
+ def configure_database
125
+ setup_database
126
+ open_database
127
+ create_scenarios_table
128
+ create_routes_table
129
+ create_testdata_table
130
+ end
131
+
132
+ def setup_database
133
+ # Create an empty database file
134
+ if !File.exists?(self.db_file)
135
+ puts self.db_file
136
+ File.open(self.db_file, 'w'){}
137
+ end
138
+ end
139
+
140
+ def open_database
141
+ # Open the database
142
+ self.db ||= Sequel.sqlite(self.db_file)
143
+ self.scenarios ||= self.db[:scenarios]
144
+ self.routes ||= self.db[:routes]
145
+ self.testdata ||= self.db[:testdata]
146
+ end
147
+
148
+ #scenarios
149
+
150
+ def create_scenarios_table
151
+ # Create Scenarios table
152
+ if !self.db.table_exists?(:scenarios)
153
+ # puts "Creating the scenarios table"
154
+ self.db.create_table :scenarios do
155
+ primary_key :id
156
+ String :name
157
+ DateTime :created_at
158
+ DateTime :updated_at
159
+ end
160
+ end
161
+ end
162
+
163
+ def add_scenario(name)
164
+ if self.scenarios.where(:name => name).to_a.count == 0
165
+ now = DateTime.now
166
+ self.scenarios.insert(:name => name, :created_at => now, :updated_at => now)
167
+ end
168
+ end
169
+
170
+ def delete_scenario(scenario_id)
171
+ self.scenarios.filter(:id => scenario_id).delete
172
+ end
173
+
174
+ def reset_scenarios
175
+ self.scenarios.delete
176
+ create_scenarios_table
177
+ end
178
+
179
+ def get_ordered_scenarios
180
+ return self.scenarios.order(:name).select(:id, :name).to_a
181
+ end
182
+
183
+ def get_scenario_names
184
+ return self.scenarios.map(:name)
185
+ end
186
+
187
+ def delete_scenario_for_id(scenario_id)
188
+ self.scenarios.filter(:id => scenario_id).delete
189
+ end
190
+
191
+ def get_scenario_for_id(scenario_id)
192
+ return self.scenarios.where(:id => scenario_id).first
193
+ end
194
+
195
+ def get_last_scenario_id
196
+ return self.scenarios.reverse_order(:id).first[:id]
197
+ end
198
+
199
+ #routes
200
+
201
+ def create_routes_table
202
+ # Create the routes table
203
+ if !self.db.table_exists?(:routes)
204
+ # puts "Creating the routes table"
205
+ self.db.create_table :routes do
206
+ primary_key :id
207
+ foreign_key :scenario_id, :scenarios, :on_delete => :cascade, :on_update => :cascade
208
+ String :route_type
209
+ String :path
210
+ String :fixture
211
+ DateTime :created_at
212
+ DateTime :updated_at
213
+ end
214
+ end
215
+ end
216
+
217
+ def add_route_for_scenario(route_type, path, fixture, scenario_id)
218
+ now = DateTime.now
219
+ if self.routes.where(:scenario_id => scenario_id, route_type=> route_type, path=> path).to_a.count == 0
220
+ self.routes.insert(:scenario_id => scenario_id, :route_type=>route_type, :path => path, :fixture => fixture, :created_at => now, :updated_at => now)
221
+ end
222
+ # puts "<scenario_id: #{scenario_id} #{}route_type} #Path: #{path} fixture: #{fixture}>"
223
+ end
224
+
225
+ def delete_route(route_id)
226
+ self.routes.filter(:id => route_id).delete
227
+ end
228
+
229
+ def get_routes_for_scenario(scenario_id)
230
+ return self.routes.filter(:scenario_id=>scenario_id).select(:id, :scenario_id,:route_type,:path,:fixture).to_a
231
+ end
232
+
233
+ def get_fixture_from_routes(route_type, path, scenario_name)
234
+
235
+ self.routes.left_outer_join(:scenarios, :id=>:scenario_id).where(:route_type=>route_type,
236
+ :path=>path,
237
+ :name=>scenario_name).map(:fixture).first
238
+
239
+
240
+ #TODO instead of returning first fixture, add checks to avoid duplicate insertions
241
+ end
242
+
243
+ def get_route(route_id)
244
+ return self.routes.where(:id => route_id).first
245
+ end
246
+
247
+ def get_last_routes_id
248
+ return self.routes.reverse_order(:id).first[:id]
249
+ end
250
+
251
+
252
+ #testdata
253
+
254
+ def create_testdata_table
255
+ # Create the testdata table
256
+ if !self.db.table_exists?(:testdata)
257
+ # puts 'Creating the testdata table'
258
+ self.db.create_table :testdata do
259
+ primary_key :id
260
+ foreign_key :scenario_id, :scenarios, :on_delete => :cascade, :on_update => :cascade
261
+ String :name
262
+ String :value
263
+ DateTime :created_at
264
+ DateTime :updated_at
265
+ end
266
+ end
267
+ end
268
+
269
+ def add_testdata_for_scenario(name, value, scenario_id)
270
+ now = DateTime.now
271
+ self.testdata.insert(:name=>name, :value=>value, :scenario_id => scenario_id, :created_at => now, :updated_at => now)
272
+ # puts "<#Name: #{name} value: #{value} scenario_id: #{scenario_id}>"
273
+ end
274
+
275
+ def delete_testdata_for_scenario(testdata_id)
276
+ self.testdata.filter(:id=>testdata_id).delete
277
+ end
278
+
279
+ def get_last_testdata_id
280
+ return self.testdata.reverse_order(:id).first[:id]
281
+ end
282
+
283
+ end
@@ -0,0 +1,3 @@
1
+ module Scenarios
2
+ VERSION = "0.0.1"
3
+ end
data/lib/scenarios.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "scenarios/version"
2
+
3
+ module Scenarios
4
+ # Your code goes here...
5
+ end
data/scenarios.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'scenarios/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "scenario_server"
8
+ spec.version = Scenarios::VERSION
9
+ spec.authors = ["Vaibhav Bhatia"]
10
+ spec.email = ["vaikings@gmail.com"]
11
+ spec.summary = %q{Scenarios is a sinatra server which returns mock json fixtures for routes in the current scenario}
12
+ spec.description = %q{This gem is useful for development where a mock rest api server is required and with frank UI test automation.}
13
+ spec.homepage = 'https://bitbucket.org/vaikings/scenarios'
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "sinatra", "~> 1.4"
22
+ spec.add_runtime_dependency "sinatra-contrib", "~> 1.4"
23
+ spec.add_runtime_dependency "sequel", "4.7"
24
+
25
+ spec.add_development_dependency "sqlite3" , "~> 1.3"
26
+ spec.add_development_dependency "bundler", "~> 1.5"
27
+ spec.add_development_dependency "rake", "~> 10.1"
28
+ spec.add_development_dependency "rack-test", "~> 0.6"
29
+ spec.add_development_dependency "rspec", "~> 2.0"
30
+ spec.add_development_dependency "json_spec", "~> 1.1"
31
+
32
+ end
data/spec/app_spec.rb ADDED
@@ -0,0 +1,149 @@
1
+ require './spec/spec_helper'
2
+ require './lib/scenarios/application/app'
3
+ require './lib/scenarios/scenario_db'
4
+
5
+
6
+ describe "scenario api" do
7
+
8
+ attr_accessor :scenario_db
9
+
10
+ before(:all) do
11
+ options = {:db_file=>File.dirname(File.expand_path(__FILE__)) + '/../lib/scenarios/data/scenario_testdb.sqlite3'}
12
+ self.scenario_db = ScenarioDB.new(options)
13
+ self.scenario_db.configure_database()
14
+
15
+ end
16
+
17
+ def app
18
+ ScenarioServer
19
+ end
20
+
21
+ before(:each) do
22
+ reset_scenario
23
+ end
24
+
25
+ it "GET /scenario" do
26
+ get '/scenario'
27
+
28
+ expect(last_response.status).to eq(200)
29
+ expect(last_response.body).to eq("default")
30
+ end
31
+
32
+ it "PUT /scenario/:name" do
33
+ put '/scenario/test'
34
+
35
+ expect(last_response.status).to eq(400)
36
+ expect(scenario).to eq("default")
37
+ end
38
+
39
+ it "PUT /scenario/:name" do
40
+ self.scenario_db.add_scenario('test')
41
+
42
+ put '/scenario/test'
43
+
44
+ expect(last_response.status).to eq(200)
45
+ expect(scenario).to eq("test")
46
+ end
47
+
48
+ it "DELETE /scenario" do
49
+ delete "/scenario"
50
+
51
+ expect(last_response.status).to eq(200)
52
+ expect(scenario).to eq("default")
53
+ end
54
+
55
+ end
56
+
57
+ describe "scenarios and routes REST api" do
58
+
59
+ def app
60
+ ScenarioServer
61
+ end
62
+
63
+ attr_accessor :scenario_db
64
+
65
+ before(:all) do
66
+ options = {:db_file=>File.dirname(File.expand_path(__FILE__)) + '/../lib/scenarios/data/scenario_testdb.sqlite3'}
67
+ self.scenario_db = ScenarioDB.new(options)
68
+ self.scenario_db.configure_database()
69
+
70
+ end
71
+
72
+ before(:each) do
73
+ self.scenario_db.reset_scenarios
74
+ scenario_id = self.scenario_db.add_scenario("default")
75
+ route_id = self.scenario_db.add_route_for_scenario('GET', '/hello', {"hello"=>"world"}.to_json, scenario_id)
76
+ end
77
+
78
+ #specs
79
+
80
+ it 'GET /scenarios' do
81
+ get '/scenarios'
82
+ expect(last_response.status).to eq(200)
83
+ file_data = parse_json(load_json('all_scenarios.json'))
84
+
85
+ last_response.body.should be_json_eql(load_json('all_scenarios.json')).excluding("id")
86
+ end
87
+
88
+ it 'GET /scenarios/{scenario_id}' do
89
+ last_scenario_id = self.scenario_db.get_last_scenario_id
90
+
91
+ get '/scenarios/'+last_scenario_id.to_s
92
+
93
+ expect(last_response.status).to eq(200)
94
+ last_response.body.should be_json_eql(load_json("default_scenario.json")).excluding("id")
95
+ end
96
+
97
+ it "POST /scenarios/new" do
98
+ post '/scenarios/new',"default",{}
99
+
100
+ expect(last_response.status).to eq(200)
101
+ last_response.body.should have_json_path("url")
102
+
103
+ end
104
+
105
+ it 'DELETE /scenarios/:scenario_id' do
106
+ last_scenario_id = self.scenario_db.get_last_scenario_id
107
+
108
+ delete '/scenarios/'+last_scenario_id.to_s
109
+ expect(last_response.status).to eq(200)
110
+ end
111
+
112
+ it 'POST /scenarios/:scenario_id/routes/new' do
113
+ last_scenario_id = self.scenario_db.get_last_scenario_id
114
+
115
+ content = '{"path":"/v1/mystyle","fixture":"{\"json\":\"body\"}","route_type":"GET" }'
116
+ path = '/scenarios/'+last_scenario_id.to_s + '/routes/new'
117
+ post path, content, {}
118
+
119
+ expect(last_response.status).to eq(200)
120
+ last_response.body.should have_json_path('url')
121
+ end
122
+
123
+ it 'GET /scenarios/:scenario_id/routes' do
124
+ last_scenario_id = self.scenario_db.get_last_scenario_id
125
+
126
+ get '/scenarios/'+last_scenario_id.to_s+'/routes'
127
+
128
+ expect(last_response.status).to eq(200)
129
+ last_response.body.should have_json_path('routes')
130
+ end
131
+
132
+ it 'DELETE /scenarios/:scenario_id/routes/:route_id' do
133
+ last_scenario_id = self.scenario_db.get_last_scenario_id
134
+ last_route_id = self.scenario_db.get_last_routes_id
135
+
136
+ delete '/scenarios/'+last_scenario_id.to_s+'/routes/'+last_route_id.to_s
137
+ expect(last_response.status).to eq(200)
138
+
139
+ end
140
+
141
+ it 'GET /scenarios/:scenario_id/routes/:route_id' do
142
+ last_scenario_id = self.scenario_db.get_last_scenario_id
143
+ last_route_id = self.scenario_db.get_last_routes_id
144
+
145
+ get '/scenarios/'+last_scenario_id.to_s+'/routes/'+last_route_id.to_s
146
+ expect(last_response.status).to eq(200)
147
+ end
148
+
149
+ end
@@ -0,0 +1,48 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ ENV["RACK_ENV"] = "test"
8
+
9
+ require 'rspec'
10
+ require 'rspec/expectations'
11
+ require 'rack/test'
12
+ require 'json_spec'
13
+
14
+ JsonSpec.directory ="./fixtures/"
15
+
16
+ RSpec.configure do |config|
17
+ config.treat_symbols_as_metadata_keys_with_true_values = true
18
+ config.run_all_when_everything_filtered = true
19
+ config.filter_run :focus
20
+
21
+ # Run specs in random order to surface order dependencies. If you find an
22
+ # order dependency and want to debug it, you can fix the order by providing
23
+ # the seed, which is printed after each run.
24
+ # --seed 1234
25
+ config.order = 'random'
26
+
27
+ #include Rack::Test::Methods by default
28
+ config.include Rack::Test::Methods
29
+ config.include JsonSpec::Helpers
30
+ end
31
+
32
+
33
+ # helper methods
34
+
35
+ def scenario
36
+ get '/scenario'
37
+ last_response.body
38
+ end
39
+
40
+ def reset_scenario
41
+ delete "/scenario"
42
+ expect(last_response.status).to eq(200)
43
+ end
44
+
45
+ def set_scenario(name)
46
+ put "/scenario/#{name}"
47
+ expect(last_response.status).to eq(200)
48
+ end