scenariotest 0.1.0

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 The Plant Co.,LTD
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,97 @@
1
+ Why
2
+ =====
3
+
4
+ I think Test Case are made up with these:
5
+
6
+ 1. Certain state (snapshot) of a whole database
7
+ 1. Code to read or change the state of the the database
8
+ 1. Assertions for the change of database state or generated http response
9
+
10
+ The current way of change the state of database are loading yaml files (Rails Fixture) or every time create objects by ActiveRecord or FactoryGirl. when you create a lots of records, it tends to be slow.
11
+
12
+ So why not use the fastest native `mysqldump` and `mysql` to load the snapshot of database for each test case.
13
+
14
+
15
+ How to use
16
+ ==========
17
+ 1. Create a ruby file like `scenarios.rb` under your test directory:
18
+
19
+ ``` ruby
20
+ S.define :dalian do
21
+ S[:dalian] = City.create!(:name => "Dalian")
22
+ end
23
+
24
+ S.define :cafes, :req => :dalian do
25
+ S[:starbucks] = Store.create!(:name => "Starbucks", :city => S[:dalian])
26
+ S[:metoo] = Store.create!(:name => "Metoo", :city => S[:dalian])
27
+ end
28
+
29
+ S.define :drinks do
30
+ S[:orange_juice] = Cafe::Drink.create!(:name => "Orange Juice", :color => 1)
31
+ S[:latte] = Cafe::Drink.create!(:name => "Latte", :color => 9)
32
+ end
33
+
34
+ S.define :starbucks_with_drinks, :req => [:cafes, :drinks] do
35
+ S[:starbucks].drinks << S[:orange_juice]
36
+ S[:starbucks].drinks << S[:latte]
37
+ end
38
+ ```
39
+ Which you can define groups of objects as scenario, can depend on other scenario you defined. So that you can use in your test case setup block.
40
+
41
+
42
+ 1. And in your test_helper.rb:
43
+
44
+ ``` ruby
45
+ ENV["RAILS_ENV"] = "test"
46
+ require File.expand_path('../../config/environment', __FILE__)
47
+ require 'rails/test_help'
48
+
49
+ S = Scenariotest::Scenario.init
50
+ require 'scenarios'
51
+ ```
52
+
53
+ 1. Then in your test file:
54
+
55
+ You can use the objects created for you freely
56
+
57
+ ``` ruby
58
+ require 'test_helper'
59
+
60
+ class Cafe::DrinkTest < ActiveSupport::TestCase
61
+ setup do
62
+ S.setup(:cafes, :drinks)
63
+ end
64
+
65
+ test "have both cafes and drinks" do
66
+ assert S[:starbucks]
67
+ assert S[:latte]
68
+ end
69
+
70
+ test "has many drinks" do
71
+ S.setup(:starbucks_with_drinks)
72
+ assert_equal(2, S[:starbucks].drinks.size, S[:starbucks].drinks.count)
73
+ assert_equal(2, Store.count, Store.count)
74
+ end
75
+
76
+ end
77
+ ```
78
+
79
+
80
+ How it works
81
+ ============
82
+
83
+ First time you call `S.setup(:starbucks_with_drinks)` it will do:
84
+
85
+ 1. empty the whole database
86
+ 1. invoke the blocks and create data from the blocks you defined and store the objects you created to `S[]`
87
+ 1. dump the database data (not schema) to tmp/scenariotest_fixtures/
88
+ 1. dump the loaded objects ids to tmp/scenariotest_fixtures/
89
+
90
+ Next time you run tests and call `S.setup(:starbucks_with_drinks)` it will do:
91
+
92
+ 1. load the dump database data
93
+ 1. load the objects into `S[]`
94
+
95
+
96
+
97
+
data/Rakefile ADDED
@@ -0,0 +1,142 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/testtask'
49
+ Rake::TestTask.new(:test) do |test|
50
+ system("cd test/dummy && rake")
51
+ end
52
+
53
+ desc "Generate RCov test coverage and open in your browser"
54
+ task :coverage do
55
+ require 'rcov'
56
+ sh "rm -fr coverage"
57
+ sh "rcov test/test_*.rb"
58
+ sh "open coverage/index.html"
59
+ end
60
+
61
+
62
+ desc "Open an irb session preloaded with this library"
63
+ task :console do
64
+ sh "irb -rubygems -r ./lib/#{name}.rb"
65
+ end
66
+
67
+ #############################################################################
68
+ #
69
+ # Custom tasks (add your own tasks here)
70
+ #
71
+ #############################################################################
72
+
73
+
74
+
75
+ #############################################################################
76
+ #
77
+ # Packaging tasks
78
+ #
79
+ #############################################################################
80
+
81
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
82
+ task :release => :build do
83
+ unless `git branch` =~ /^\* master$/
84
+ puts "You must be on the master branch to release!"
85
+ exit!
86
+ end
87
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
88
+ sh "git tag v#{version}"
89
+ sh "git push origin master"
90
+ sh "git push origin v#{version}"
91
+ sh "gem push pkg/#{name}-#{version}.gem"
92
+ end
93
+
94
+ desc "Build #{gem_file} into the pkg directory"
95
+ task :build => :gemspec do
96
+ sh "mkdir -p pkg"
97
+ sh "gem build #{gemspec_file}"
98
+ sh "mv #{gem_file} pkg"
99
+ end
100
+
101
+ desc "Generate #{gemspec_file}"
102
+ task :gemspec => :validate do
103
+ # read spec file and split out manifest section
104
+ spec = File.read(gemspec_file)
105
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
106
+
107
+ # replace name version and date
108
+ replace_header(head, :name)
109
+ replace_header(head, :version)
110
+ replace_header(head, :date)
111
+ #comment this out if your rubyforge_project has a different name
112
+ replace_header(head, :rubyforge_project)
113
+
114
+ # determine file list from git ls-files
115
+ files = `git ls-files`.
116
+ split("\n").
117
+ sort.
118
+ reject { |file| file =~ /^\./ }.
119
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
120
+ reject { |file| file =~ /^(test)/ }.
121
+ map { |file| " #{file}" }.
122
+ join("\n")
123
+
124
+ # piece file back together and write
125
+ manifest = " s.files = %w[\n#{files}\n ]\n"
126
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
127
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
128
+ puts "Updated #{gemspec_file}"
129
+ end
130
+
131
+ desc "Validate #{gemspec_file}"
132
+ task :validate do
133
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
134
+ unless libfiles.empty?
135
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
136
+ exit!
137
+ end
138
+ unless Dir['VERSION*'].empty?
139
+ puts "A `VERSION` file at root level violates Gem best practices."
140
+ exit!
141
+ end
142
+ end
@@ -0,0 +1,207 @@
1
+ require "active_record"
2
+ module Scenariotest
3
+ class Driver
4
+
5
+ def self.start(app)
6
+ new(app).start
7
+ end
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def find_cmd(*commands)
14
+ dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
15
+ commands += commands.map{|cmd| "#{cmd}.exe"} if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
16
+
17
+ full_path_command = nil
18
+ found = commands.detect do |cmd|
19
+ dir = dirs_on_path.detect do |path|
20
+ full_path_command = File.join(path, cmd)
21
+ File.executable? full_path_command
22
+ end
23
+ end
24
+ found ? full_path_command : abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
25
+ end
26
+
27
+ def config
28
+ @config ||= begin
29
+ database_config = @app.config.database_configuration
30
+ unless c = database_config[Rails.env]
31
+ abort "No database is configured for the environment '#{Rails.env}'"
32
+ end
33
+ c
34
+ end
35
+ end
36
+
37
+ def run(type, file, options={})
38
+ cmd = case config["adapter"]
39
+ when /^mysql/
40
+ args = {
41
+ 'host' => '--host',
42
+ 'port' => '--port',
43
+ 'socket' => '--socket',
44
+ 'username' => '--user',
45
+ 'encoding' => '--default-character-set',
46
+ 'password' => '--password'
47
+ }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
48
+
49
+ args << (options.map do |name, value|
50
+ if value.blank?
51
+ " #{name}"
52
+ else
53
+ " #{name}=#{value}"
54
+ end
55
+ end).join("")
56
+
57
+ args << config['database']
58
+
59
+ commands, direct = if type == 'dump'
60
+ [['mysqldump', 'mysqldump5'], ">>"]
61
+ else
62
+ [['mysql', 'mysql5'], "<"]
63
+ end
64
+ [find_cmd(*commands), args.join(" "), direct, file].join(" ")
65
+
66
+ when "postgresql", "postgres"
67
+ ENV['PGUSER'] = config["username"] if config["username"]
68
+ ENV['PGHOST'] = config["host"] if config["host"]
69
+ ENV['PGPORT'] = config["port"].to_s if config["port"]
70
+ ENV['PGPASSWORD'] = config["password"].to_s if config["password"]
71
+
72
+ commands, direct = if type == 'dump'
73
+ [['psqldump'], ">>"]
74
+ else
75
+ [['psql'], "<"]
76
+ end
77
+
78
+ [find_cmd(*commands), config["database"], direct, file].join(" ")
79
+ end
80
+
81
+ Rails.logger.debug(" Scenariotest: #{cmd}")
82
+ raise "failed running #{cmd}" unless system(cmd)
83
+ true
84
+ end
85
+
86
+ def dump_file(name, source_sha1, type = "sql")
87
+ f = "#{@app.root}/tmp/scenariotest_fixtures/#{name}_#{source_sha1}.#{type}"
88
+ FileUtils.mkdir_p(File.dirname(f)) unless File.exist?(File.dirname(f))
89
+ f
90
+ end
91
+
92
+ class << self
93
+ def instance
94
+ @instance ||= new(Rails.application)
95
+ end
96
+ end
97
+
98
+ def setup(senario_klass, method_names)
99
+ definations = senario_klass.definations
100
+
101
+ method_name = if method_names.length > 1
102
+ sha1s = method_names.map{|name| definations[name].nil? ? senario_klass.not_defined!(name) : definations[name].sha1}
103
+ collection_sha1 = if sha1s.uniq.size == 1
104
+ sha1s[0]
105
+ else
106
+ Digest::SHA1.hexdigest(sha1s.join("\n"))
107
+ end
108
+ m = "__#{method_names.join("_")}".to_sym
109
+ senario_klass.define(m, :req => method_names, :source_sha1 => collection_sha1) {} unless definations[m]
110
+ m
111
+ else
112
+ method_names[0]
113
+ end
114
+
115
+ ActiveSupport::Notifications.instrument('setup.scenariotest', :name => "%s" % [method_name]) do
116
+ Rails.logger.info("\n\n* Scenariotest Setup Started: #{method_name}")
117
+ senario_klass.invoke(method_name)
118
+ end
119
+ end
120
+
121
+
122
+ def empty_data(source_sha1)
123
+ f = dump_file("empty_data", source_sha1, "sql")
124
+ unless File.exist?(f)
125
+ truncate_sql = ActiveRecord::Base.connection.tables.map{|t| "TRUNCATE `#{t}`;"}.join("\n")
126
+ File.open(f, "w"){|fh| fh.write("-- clear data\n" << truncate_sql)}
127
+ # run("dump", f, "--no-data" => nil, "--ignore-table"=>"#{config['database']}.schema_migration")
128
+ end
129
+ run("load", f)
130
+ end
131
+
132
+ def can_load?(name, source_sha1)
133
+ f = dump_file(name, source_sha1, "sql")
134
+ return false unless File.exist?(f)
135
+ yml_file = dump_file(name, source_sha1, "objects.yml")
136
+ return false unless File.exist?(yml_file)
137
+ true
138
+ end
139
+
140
+ def load(name, source_sha1)
141
+ f = dump_file(name, source_sha1, "sql")
142
+ return false unless File.exist?(f)
143
+ yml_file = dump_file(name, source_sha1, "objects.yml")
144
+ return false unless File.exist?(yml_file)
145
+
146
+ ActiveSupport::Notifications.instrument('load.scenariotest', :name => "%s (%s)" % [name, source_sha1]) do
147
+
148
+ run("load", f)
149
+
150
+ objs = YAML.load_file(yml_file)
151
+
152
+ klass_ids_map = {}
153
+ objs.each do |name, obj|
154
+ (if !obj[0].is_a?(Array)
155
+ [obj]
156
+ else
157
+ obj
158
+ end).each{|klass, id| (klass_ids_map[klass] ||= []) << id}
159
+ end
160
+
161
+ objs_identity_map = {}
162
+ klass_ids_map.each do |klass, ids|
163
+ klass.constantize.find(ids).each do |obj|
164
+ objs_identity_map["#{klass}_#{obj.id}"] = obj
165
+ end
166
+ end
167
+
168
+
169
+ objs.each do |name, obj|
170
+ loaded_obj = if obj[0].is_a?(Array)
171
+ obj.map{|klass, id| objs_identity_map["#{klass}_#{id}"]}
172
+ else
173
+ objs_identity_map["#{obj[0]}_#{obj[1]}"]
174
+ end
175
+ Scenariotest::Scenario[name] = loaded_obj
176
+ end
177
+
178
+ end
179
+ true
180
+ end
181
+
182
+ def dump(name, source_sha1, changed_data, truncate = true)
183
+ ActiveSupport::Notifications.instrument('dump.scenariotest', :name => "%s (%s)" % [name, source_sha1]) do
184
+
185
+ File.open(dump_file(name, source_sha1, "objects.yml"), 'wb') do |f|
186
+ YAML.dump(changed_data, f)
187
+ end
188
+
189
+ if truncate
190
+ File.open(dump_file(name, source_sha1, "sql"), 'wb') do |f|
191
+ truncate_sql = ActiveRecord::Base.connection.tables.map{|t| "TRUNCATE `#{t}`;"}.join("\n")
192
+ f.write("-- clear data start\n" << truncate_sql << "\n-- clear data end\n\n")
193
+ end
194
+ end
195
+
196
+ run("dump", dump_file(name, source_sha1, "sql"),
197
+ "--no-create-info" => nil,
198
+ "--skip-add-locks" => nil,
199
+ "--skip-triggers" => nil)
200
+
201
+ end
202
+ end
203
+
204
+ end
205
+ end
206
+
207
+
@@ -0,0 +1,24 @@
1
+ module Scenariotest
2
+ class LogSubscriber < ActiveSupport::LogSubscriber
3
+ def load(event)
4
+ name = event.payload[:name]
5
+ info " " << color("Scenariotest Loaded (%.1fms) %s" % [event.duration, name], GREEN, false).to_s
6
+ end
7
+
8
+ def dump(event)
9
+ name = event.payload[:name]
10
+ info " " << color("Scenariotest Dumped (%.1fms) %s" % [event.duration, name], YELLOW, false).to_s
11
+ end
12
+
13
+ def setup(event)
14
+ name = event.payload[:name]
15
+ info " " << color("Scenariotest Setup Finished (%.1fms) %s" % [event.duration, name], MAGENTA, true).to_s << "\n\n"
16
+ end
17
+
18
+ def logger
19
+ ActiveRecord::Base.logger
20
+ end
21
+ end
22
+ end
23
+
24
+ Scenariotest::LogSubscriber.attach_to :scenariotest
@@ -0,0 +1,170 @@
1
+ require 'scenariotest/driver'
2
+ require 'scenariotest/log_subscriber'
3
+ require 'digest'
4
+
5
+ module Scenariotest
6
+ VERSION = "0.1.0"
7
+ class Scenario
8
+ class Defination
9
+ attr_accessor :name, :sha1, :options, :main_blk, :after_blk, :scenario_klass
10
+
11
+ def initialize(scenario_klass, name, options, blk)
12
+ self.scenario_klass = scenario_klass
13
+ self.sha1 = options[:source_sha1]
14
+ self.sha1 ||= begin
15
+ source_path = blk.source_location[0].dup
16
+ Digest::SHA1.hexdigest(source_path << File.read(source_path))
17
+ end
18
+ self.name = name
19
+ self.options = options
20
+ self.main_blk = blk
21
+
22
+ end
23
+
24
+ def root?
25
+ self.options[:req].blank?
26
+ end
27
+
28
+ def root_cache_name
29
+ "___root_#{self.name}"
30
+ end
31
+
32
+ def call
33
+ loaded = scenario_klass.driver.load(self.name, sha1)
34
+
35
+ deps = uniq_dependencies
36
+
37
+ unless loaded
38
+
39
+ # dump all the reuseable roots
40
+ roots = deps.select{|d| d.root? }
41
+ roots.each do |dep|
42
+ next if scenario_klass.driver.can_load?(dep.root_cache_name, dep.sha1)
43
+ scenario_klass.driver.empty_data(sha1)
44
+ dep_changed_data = scenario_klass.changed do
45
+ dep.main_blk.call
46
+ end
47
+ scenario_klass.driver.dump(dep.root_cache_name, dep.sha1, dep_changed_data, false)
48
+ end
49
+
50
+ scenario_klass.driver.empty_data(sha1)
51
+ changed_data = scenario_klass.changed do
52
+ deps.each do |dep|
53
+ if dep.root? && scenario_klass.driver.load(dep.root_cache_name, dep.sha1) # only no dependencies scenarios can be cached
54
+ # loaded from dump
55
+ else
56
+ dep.main_blk.call
57
+ end
58
+ end
59
+
60
+ self.main_blk.call
61
+
62
+ end
63
+
64
+ scenario_klass.driver.dump(name, sha1, changed_data)
65
+
66
+ end
67
+
68
+ deps.each {|dep| dep.after_blk.call if dep.after_blk }
69
+ self.after_blk.call if self.after_blk
70
+ nil
71
+ end
72
+
73
+ def uniq_dependencies(list = [])
74
+ [self.options[:req]].flatten.compact.reverse.each do |name|
75
+ dep = scenario_klass.definations[name]
76
+ scenario_klass.not_defined!(name) if dep.nil?
77
+ dep.uniq_dependencies(list)
78
+ list << dep unless list.include?(dep)
79
+ end
80
+ list
81
+ end
82
+
83
+ end
84
+
85
+ class << self
86
+ def init
87
+ log("Fixtures are disabled when using Scenariotest.")
88
+ ActiveRecord::TestFixtures.class_eval <<-EOF
89
+ def setup_fixtures
90
+ end
91
+ def teardown_fixtures
92
+ end
93
+ EOF
94
+ @data = {}
95
+ @changed_data_stack = [{}]
96
+ self
97
+ end
98
+
99
+ def data
100
+ @data
101
+ end
102
+
103
+ def driver
104
+ @driver ||= Scenariotest::Driver.instance
105
+ end
106
+
107
+ def log(message)
108
+ Rails.logger.info(message) if const_defined?(:Rails)
109
+ end
110
+
111
+ def []=(name, value)
112
+ return if value.nil?
113
+ changed_data_value = if value.is_a?(Array)
114
+ value.map{|v| [v.class.name, v.id]}
115
+ else
116
+ [value.class.name, value.id]
117
+ end
118
+
119
+ @changed_data_stack[-1][name] = changed_data_value
120
+ @data[name] = value
121
+ end
122
+
123
+ def changed(&blk)
124
+ @changed_data_stack << {}
125
+ blk.call
126
+ changed = @changed_data_stack.pop
127
+ # if @changed_data_stack[-1]
128
+ # @changed_data_stack[-1].update(changed)
129
+ # end
130
+ changed
131
+ end
132
+
133
+ def [](name)
134
+ @data[name]
135
+ end
136
+
137
+ def reload
138
+ load __FILE__
139
+ end
140
+
141
+
142
+ def define name, options = {}, &blk
143
+ definations[name] = Defination.new(self, name, options, blk)
144
+ end
145
+
146
+ def after name, &blk
147
+ not_defined!(name) unless definations[name]
148
+ definations[name].after_blk = blk
149
+ end
150
+
151
+ def setup(*names)
152
+ self.driver.setup(self, names)
153
+ end
154
+
155
+ def invoke(name)
156
+ (load_or_dump = definations[name]) ? load_or_dump.call : not_defined!(name)
157
+ end
158
+
159
+ def definations
160
+ (@definations ||= {})
161
+ end
162
+
163
+ def not_defined!(name)
164
+ raise("`#{name.inspect}' not defined.")
165
+ end
166
+
167
+ end
168
+ end
169
+
170
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.specification_version = 2 if s.respond_to? :specification_version=
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.rubygems_version = '1.3.5'
7
+
8
+ s.platform = Gem::Platform::RUBY
9
+
10
+ s.name = "scenariotest"
11
+ s.version = "0.1.0"
12
+ s.date = "2012-02-07"
13
+
14
+ s.authors = ["Felix Sun"]
15
+ s.email = %q{felix@theplant.jp}
16
+
17
+ s.homepage = %q{http://github.com/theplant/senariotest}
18
+ s.summary = %q{Senario Test}
19
+ s.description = %q{Senario Test}
20
+
21
+ s.files = Dir["{app,lib,public,config}/**/*"] + %w{LICENSE README.markdown}
22
+ s.require_path = "lib"
23
+
24
+ s.required_ruby_version = ">= 1.8.7"
25
+
26
+ s.extra_rdoc_files = ["README.markdown"]
27
+
28
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
29
+ # = MANIFEST =
30
+ s.files = %w[
31
+ LICENSE
32
+ README.markdown
33
+ Rakefile
34
+ lib/scenariotest.rb
35
+ lib/scenariotest/driver.rb
36
+ lib/scenariotest/log_subscriber.rb
37
+ scenariotest.gemspec
38
+ ]
39
+ # = MANIFEST =
40
+
41
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scenariotest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Felix Sun
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Senario Test
15
+ email: felix@theplant.jp
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.markdown
20
+ files:
21
+ - LICENSE
22
+ - README.markdown
23
+ - Rakefile
24
+ - lib/scenariotest.rb
25
+ - lib/scenariotest/driver.rb
26
+ - lib/scenariotest/log_subscriber.rb
27
+ - scenariotest.gemspec
28
+ homepage: http://github.com/theplant/senariotest
29
+ licenses: []
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: 1.8.7
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.8.7
49
+ signing_key:
50
+ specification_version: 2
51
+ summary: Senario Test
52
+ test_files: []
53
+ has_rdoc: