app-tester 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,264 @@
1
+ # Application Tester (app-tester)
2
+
3
+ * http://github.com/joseairosa/app-tester
4
+
5
+ [![Build Status](https://secure.travis-ci.org/joseairosa/app-tester.png)](http://travis-ci.org/joseairosa/app-tester)
6
+
7
+ ## DESCRIPTION:
8
+
9
+ This Gem will provide a framework to build command line functional tests against a web application (API, Website, etc)
10
+
11
+ ## FEATURES/PROBLEMS:
12
+
13
+ * Easily create functional tests with just a few lines of code
14
+ * Since tests are built as command line tools they can be easily integrated with automatic tools
15
+ * Specify command line options in both short (-s, -f, etc...) and long (--server, --file, etc...) definition
16
+ * Add colors to make your tests more readable and easier to understand
17
+ * Use pre-built tools to analyse your output or build your own
18
+
19
+ ## SYNOPSIS:
20
+
21
+ ```ruby
22
+ require "app-tester"
23
+
24
+ # Initialize framework with test environments
25
+ apptester = AppTester.new do |options|
26
+ options.add_environment :github => "https://github.com"
27
+ options.add_environment :google => "https://google.com"
28
+ options.default_environment = :google # A default environment can be specified
29
+ end
30
+
31
+ # Define your tests
32
+ apptester.define_test "my test" do |cmd_options, connection|
33
+ result = connection.get do |request|
34
+ request.url "/"
35
+ end
36
+
37
+ # Check if we have a 200 OK or not
38
+ AppTester::Checker.status result
39
+
40
+ # Convert a file to an array
41
+ p AppTester::Utils.file_to_array cmd_options[:file] unless cmd_options[:file].nil?
42
+ end
43
+
44
+ apptester.set_options_for "my test" do |options_parser|
45
+ options_parser.set_option(:file, "-f", "--file FILE", "File to load")
46
+ options_parser.mandatory_options = 1
47
+ end
48
+
49
+ apptester.run_test "my test"
50
+ ```
51
+
52
+ Assuming that this is in a file called my_test.rb, you can run it, via command line:
53
+
54
+ ```
55
+ $ ruby my_test.rb --help
56
+ ```
57
+
58
+ Will output:
59
+
60
+ ```
61
+ my test
62
+
63
+ -s, --server OPT Server to connect. Default: google
64
+ -f, --file FILE File to load
65
+ -h, --help Show this message
66
+ ```
67
+
68
+ Or you can run the test itself:
69
+
70
+ ```
71
+ $ ruby my_test.rb -s github
72
+ ```
73
+
74
+ Will output:
75
+
76
+ ```
77
+ Connecting to https://github.com...
78
+ [SUCCESS] got status 200
79
+ ```
80
+
81
+ ## REQUIREMENTS:
82
+
83
+ * json >= 1.7.5
84
+ * faraday >= 0.8.4
85
+ * optparse
86
+
87
+ ## INSTALL:
88
+
89
+ It's very easy to install.
90
+
91
+ ```
92
+ gem install app-tester
93
+ ```
94
+
95
+ Done! :)
96
+
97
+ ## Adding colours to your tests
98
+
99
+ AppTester has a useful helper class that enables anyone to add colours to the tests.
100
+ Lets take the example where we want to output "Hello World" in 2 different colours.
101
+
102
+ ```ruby
103
+ require "app-tester"
104
+
105
+ # Initialize framework with test environments
106
+ apptester = AppTester.new do |options|
107
+ options.add_environment :github => "https://github.com"
108
+ options.default_environment = :github # A default environment can be specified
109
+ end
110
+
111
+ # Define your tests
112
+ apptester.define_test "my test" do |cmd_options, connection|
113
+ result = connection.get do |request|
114
+ request.url "/"
115
+ end
116
+
117
+ puts "#{AppTester::Utils::Colours.red("Hello")} #{AppTester::Utils::Colours.green("World")}"
118
+ end
119
+
120
+ apptester.run_test "my test"
121
+ ```
122
+
123
+ Available colours are:
124
+
125
+ * black
126
+ * blue
127
+ * green
128
+ * cyan
129
+ * red
130
+ * purple
131
+ * brown
132
+ * light_gray
133
+ * dark_gray
134
+ * light_blue
135
+ * light_green
136
+ * light_cyan
137
+ * light_red
138
+ * light_purple
139
+ * yellow
140
+ * white
141
+
142
+ ## Benchmarking
143
+
144
+ You can benchmark your test. This is very useful to understand if anything is underperforming.
145
+ Tests can be nested inside each other.
146
+
147
+ ```
148
+ require "app-tester"
149
+
150
+ # Initialize framework with test environments
151
+ apptester = AppTester.new do |options|
152
+ options.add_environment :github => "https://github.com"
153
+ options.default_environment = :github # A default environment can be specified
154
+ end
155
+
156
+ # Define your tests
157
+ apptester.define_test "my test" do |cmd_options, connection|
158
+ result = connection.get do |request|
159
+ request.url "/"
160
+ end
161
+
162
+ AppTester::Timer.new("test timer 1") do
163
+ sleep 1
164
+ end
165
+
166
+ AppTester::Timer.new("test timer 2") do
167
+ sleep 1
168
+ AppTester::Timer.new("test timer 2.1") do
169
+ sleep 1
170
+ end
171
+ end
172
+ end
173
+
174
+ apptester.run_test "my test"
175
+ ```
176
+
177
+ This will output:
178
+
179
+ ```
180
+ $ ruby examples/benchmark.rb
181
+ Connecting to https://github.com...
182
+ Time elapsed to test timer 1, 1001.086 milliseconds
183
+ Time elapsed to test timer 2.1, 1000.12 milliseconds
184
+ Time elapsed to test timer 2, 2001.204 milliseconds
185
+ ```
186
+
187
+ ## Reading from a file
188
+
189
+ File are extremely usefull tools.
190
+ We can have, for example, a functional test to an API where we want to run 100 strings against an end-point. For this you only need to create a new plain text file, write 1 string per line and use this gem to read them.
191
+
192
+ Here is an example:
193
+
194
+ ```
195
+ require "app-tester"
196
+
197
+ apptester = AppTester.new do |options|
198
+ options.add_environment :github => "https://github.com"
199
+ options.add_environment :google => "https://google.com"
200
+ options.default_environment = :google
201
+ end
202
+
203
+ apptester.define_test "my test" do |cmd_options, connection|
204
+ result = connection.get do |request|
205
+ request.url "/"
206
+ end
207
+ AppTester::Checker.status result
208
+
209
+ my_file = AppTester::Utils.file_to_array cmd_options[:file]
210
+
211
+ my_file.each do |line|
212
+ # do awesome stuff with line
213
+ end
214
+ end
215
+
216
+ apptester.set_options_for "my test" do |options_parser|
217
+ options_parser.set_option(:file, "-f", "--file FILE", "File to load")
218
+ options_parser.mandatory_options = 1
219
+ end
220
+
221
+ apptester.run_test "my test"
222
+ ```
223
+
224
+ ## Supported Ruby versions
225
+
226
+ This library aims to support and is tested against the following Ruby
227
+ implementations:
228
+
229
+ * MRI 1.8.7
230
+ * MRI 1.9.2
231
+ * MRI 1.9.3
232
+ * [JRuby][]
233
+ * [Rubinius][]
234
+
235
+ If something doesn't work on one of these interpreters, it should be considered
236
+ a bug.
237
+
238
+ ## LICENSE:
239
+
240
+ (The MIT License)
241
+
242
+ Copyright (c) 2012 José P. Airosa
243
+
244
+ Permission is hereby granted, free of charge, to any person obtaining
245
+ a copy of this software and associated documentation files (the
246
+ 'Software'), to deal in the Software without restriction, including
247
+ without limitation the rights to use, copy, modify, merge, publish,
248
+ distribute, sublicense, and/or sell copies of the Software, and to
249
+ permit persons to whom the Software is furnished to do so, subject to
250
+ the following conditions:
251
+
252
+ The above copyright notice and this permission notice shall be
253
+ included in all copies or substantial portions of the Software.
254
+
255
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
256
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
257
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
258
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
259
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
260
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
261
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
262
+
263
+ [jruby]: http://jruby.org/
264
+ [rubinius]: http://rubini.us/
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ gem "json", "~> 1.7.5"
4
+ gem "faraday", "~> 0.8.4"
5
+ require 'hoe'
6
+ require 'fileutils'
7
+ require './lib/app-tester'
8
+
9
+ Hoe.plugin :newgem
10
+ # Hoe.plugin :website
11
+ # Hoe.plugin :cucumberfeatures
12
+
13
+ # Generate all the Rake tasks
14
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
15
+ $hoe = Hoe.spec 'app-tester' do
16
+ self.developer 'Jose P. Airosa', 'me@joseairosa.com'
17
+ #self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
18
+ self.rubyforge_name = self.name # TODO this is default value
19
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
20
+
21
+ end
22
+
23
+ require 'newgem/tasks'
24
+ Dir['tasks/**/*.rake'].each { |t| load t }
25
+
26
+ # TODO - want other tests/tasks run by default? Add them to the list
27
+ # remove_task :default
28
+ task :default => [:rspec]
@@ -0,0 +1,31 @@
1
+ module AppTester
2
+ # @abstract Check module to be used within a test snippet. This can be extended to have more checks
3
+ module Checker
4
+ extend self
5
+
6
+ # Check the status of a response and output to cmd
7
+ #
8
+ # @param response [Faraday::Response] the response object from Faraday
9
+ # @param overwrite_output [NilClass, TrueClass] if we should overwrite default output. Useful for setting custom messages
10
+ # @param fail [TrueClass, FalseClass] if we should force the script to halt execution
11
+ #
12
+ # @return [NilClass]
13
+ def status(response, overwrite_output=nil, fail=false)
14
+ if response.status == 200
15
+ if overwrite_output.nil?
16
+ puts "#{AppTester::Utils::Strings::SUCCESS} got status #{response.status}"
17
+ else
18
+ puts "#{AppTester::Utils::Strings::SUCCESS} #{overwrite_output}"
19
+ end
20
+ else
21
+ if overwrite_output.nil?
22
+ puts "#{AppTester::Utils::Strings::WARNING} got status #{response.status}"
23
+ else
24
+ puts "#{AppTester::Utils::Strings::WARNING} #{overwrite_output}"
25
+ end
26
+ exit(1) if fail
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ require "faraday"
2
+
3
+ module AppTester
4
+ # @abstract Connection object that deals with communicating with Faraday to build new connections
5
+ # @attr_reader options [AppTester::Options] the options that the user defined when he created the framework
6
+ class Connection
7
+
8
+ attr_reader :options
9
+
10
+ # Build a new connection handler
11
+ #
12
+ # @param url [String] the url that will be used to set up a new connection handler
13
+ # @param options [AppTester::Options] the options that the user defined when he created the framework
14
+ #
15
+ # @raise [OptionParser::InvalidArgument] if no url is specified
16
+ # @raise [Faraday::Error::ConnectionFailed] if there was a problem connecting to the url provided
17
+ #
18
+ # @return [Faraday::Connection] on successfull connection
19
+ #
20
+ # @todo Implement connection retry
21
+ def self.new(url="", options={})
22
+ @options = options
23
+
24
+ # Make sure server choice makes sense
25
+ raise OptionParser::InvalidArgument if url.nil?
26
+
27
+ puts AppTester::Utils::Colours.dark_gray "Connecting to #{url}..."
28
+ retries = 0
29
+ connection = Faraday.new(:url => url, :ssl => { :verify => false }) do |builder|
30
+ builder.request :url_encoded
31
+ builder.adapter :net_http
32
+ builder.response :logger if @options.log_connections
33
+ end
34
+ connection
35
+ #begin
36
+ #
37
+ # connection.get do |req|
38
+ #
39
+ # end
40
+ #rescue Faraday::Error::ConnectionFailed => e
41
+ # retries += 1
42
+ # if retries <= @options.connection_retries
43
+ # puts AppTester::Utils::Colours.dark_gray "#{AppTester::Utils::Strings::FAILED} Failed connection to #{url}, retry attempt #{retries}..."
44
+ # retry
45
+ # end
46
+ # raise Faraday::Error::ConnectionFailed(e.message)
47
+ #end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ module AppTester
2
+ class Core
3
+ def initialize
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module AppTester
2
+ module Error
3
+ class NameEmptyError < StandardError
4
+ end
5
+ class BlockNotGivenError < StandardError
6
+ end
7
+ class TestNotFoundError < StandardError
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ module AppTester
2
+ # @abstract Framework options
3
+ # @attr_accessor default_environment [Symbol] the default environment in case command line script is executed without a server defined
4
+ # @attr_accessor environments [Hash] the list of environments
5
+ # @attr_accessor log_connection [TrueClass, FalseClass] if we should or not log Faraday connections
6
+ # @todo implement connection retries
7
+ class Options
8
+
9
+ attr_accessor :default_environment
10
+ attr_accessor :log_connections
11
+ attr_accessor :environments
12
+ #attr_accessor :connection_retries
13
+
14
+ def initialize
15
+ @environments = {}
16
+ @default_environment = nil
17
+ @log_connections = false
18
+ #@connection_retries = 0
19
+ end
20
+
21
+ # Add a new environment to the environment list. This will be used when constructing AppTester::Parser object
22
+ #
23
+ # @param environment [Hash] Symbol to String mapping
24
+ #
25
+ # @return [AppTester::Options] returns self
26
+ def add_environment environment
27
+ @environments.merge! environment
28
+ self
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,60 @@
1
+ require "optparse"
2
+
3
+ module AppTester
4
+ # @abstract Parser handler for command line options. This uses optparse ruby gem
5
+ # @see http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html
6
+ # @attr_reader test_options [AppTester::Options] the options that the user defined when he created the framework
7
+ # @attr_reader options [Hash] command line arguments that were set when executing the script
8
+ # @attr_writer mandatory_options [Number] minimum number of command line arguments for this script to run
9
+ class Parser < OptionParser
10
+
11
+ attr_reader :test_options
12
+ attr_reader :options
13
+
14
+ attr_accessor :mandatory_options
15
+
16
+ # Build Parser object. Automatically builds with --server argument
17
+ #
18
+ # @param options [AppTester::Options] the options that the user defined when he created the framework
19
+ #
20
+ # @return [AppTester::Parser]
21
+ def initialize options
22
+ @options = { }
23
+ @test_options = options
24
+ @mandatory_options = 0
25
+ super do |x|
26
+ x.separator ''
27
+ end
28
+
29
+ # Fallback to the first entry on the environments list if there's not default environment selected
30
+ default_environment = @test_options.default_environment.nil? ? @test_options.environments.keys.first : @test_options.default_environment
31
+ @options[:server] = @test_options.environments[default_environment]
32
+
33
+ set_option(:server, "-s", "--server OPT", @test_options.environments.keys, "Server to connect. Default: #{default_environment}")
34
+ end
35
+
36
+ # Add a new option to our optparser
37
+ #
38
+ # @param symbol [Symbol] identifier that will be used on the yielded block on define_test
39
+ # @param opts [String] command line options definition
40
+ # @param block [Proc] custom code to be executed. Optional
41
+ #
42
+ # @see AppTester
43
+ # @see OptionParser
44
+ def set_option(symbol, *opts, &block)
45
+ if block.nil?
46
+ on(*opts) do |x|
47
+ case symbol
48
+ when :server
49
+ @options[symbol] = @test_options.environments[x]
50
+ else
51
+ @options[symbol] = x
52
+ end
53
+ end
54
+ else
55
+ on(*opts, &block)
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,49 @@
1
+ module AppTester
2
+ # @abstract Main object that hold all the data needed to run a test
3
+ # @attr_reader parser [AppTester::Parser] user selected options on command line
4
+ # @attr_reader name [String] name for this test
5
+ # @attr_reader source [Proc] block of code that holds the test to be executed
6
+ # @attr_reader connection [Faraday::Connection] connection handler
7
+ # @attr_reader options [AppTester::Options] the options that the user defined when he created the framework
8
+ class Test < Core
9
+
10
+ attr_reader :parser
11
+ attr_reader :name
12
+ attr_reader :source
13
+ attr_reader :connection
14
+ attr_reader :options
15
+
16
+ def initialize name, options={ }
17
+ @name = name
18
+ @options = options
19
+ @source = Proc.new { |parser_options, connection| yield(parser_options, connection) }
20
+ @parser = AppTester::Parser.new(options)
21
+ @parser.banner = @name
22
+ end
23
+
24
+ # Defines command options (arguments) that this test supports
25
+ def set_cmd_options
26
+ yield(@parser) if block_given?
27
+ end
28
+
29
+ # Run test
30
+ def run(arguments=ARGV)
31
+ append_help_option
32
+ @parser.parse!(arguments)
33
+ # Make sure we have enough arguments
34
+ raise OptionParser::MissingArgument if @parser.mandatory_options + 2 > @parser.options.size + 1
35
+ @connection = AppTester::Connection.new @parser.options[:server], @options
36
+ @source.call(@parser.options, @connection)
37
+ end
38
+
39
+ private
40
+
41
+ # Appends helper option. This options is always available on every test
42
+ def append_help_option
43
+ @parser.set_option(nil, "-h", "--help", "Show this message") do
44
+ puts @parser
45
+ exit
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,45 @@
1
+ module AppTester
2
+ # @abstract Benchmark helper class
3
+ class Timer
4
+
5
+ # Created a new timer object
6
+ #
7
+ # @param message [NilClass, String] custom message to be displayed
8
+ # @param threshold [Number] amount in ms. If this limit is passed a warning message will be displayed
9
+ # @param method [NilClass, Symbol] method to benchmark. Optional
10
+ # @param args [NilClass, String] arguments to be passed onto the method
11
+ #
12
+ # @yield code snipper to be benchmarked
13
+ #
14
+ # @example
15
+ # apptester.define_test "my test 400 threshold" do |options, connection|
16
+ # AppTester::Timer.new("test timer", 400) do
17
+ # sleep 0.5
18
+ # end
19
+ # end
20
+ def initialize(message=nil, threshold=nil, method=nil, *args)
21
+ beginning_time = Time.now
22
+ if block_given?
23
+ yield
24
+ else
25
+ self.send(method, args)
26
+ end
27
+ end_time = Time.now
28
+ time_passed = ((end_time - beginning_time)*1000).round(3)
29
+ printf " "
30
+
31
+ threshold_message = ""
32
+ unless threshold.nil?
33
+ printf "#{AppTester::Utils::Strings::WARNING} " if time_passed.to_f > threshold.to_f
34
+ threshold_message = " (threshold: #{threshold} ms)"
35
+ end
36
+
37
+ if message.nil?
38
+ puts AppTester::Utils::Colours.dark_gray "Time elapsed #{time_passed} milliseconds#{threshold_message}"
39
+ else
40
+ puts AppTester::Utils::Colours.dark_gray "Time elapsed to #{message}, #{time_passed} milliseconds#{threshold_message}"
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,61 @@
1
+ module AppTester
2
+ module Utils
3
+ module Colours
4
+
5
+ extend self
6
+
7
+ def black message=""
8
+ _build_message("0;30", message)
9
+ end
10
+ def blue message=""
11
+ _build_message("0;34", message)
12
+ end
13
+ def green message=""
14
+ _build_message("0;32", message)
15
+ end
16
+ def cyan message=""
17
+ _build_message("0;36", message)
18
+ end
19
+ def red message=""
20
+ _build_message("0;31", message)
21
+ end
22
+ def purple message=""
23
+ _build_message("0;35", message)
24
+ end
25
+ def brown message=""
26
+ _build_message("0;33", message)
27
+ end
28
+ def light_gray message=""
29
+ _build_message("0;37", message)
30
+ end
31
+ def dark_gray message=""
32
+ _build_message("1;30", message)
33
+ end
34
+ def light_blue message=""
35
+ _build_message("1;34", message)
36
+ end
37
+ def light_green message=""
38
+ _build_message("1;32", message)
39
+ end
40
+ def light_cyan message=""
41
+ _build_message("1;36", message)
42
+ end
43
+ def light_red message=""
44
+ _build_message("1;31", message)
45
+ end
46
+ def light_purple message=""
47
+ _build_message("1;35", message)
48
+ end
49
+ def yellow message=""
50
+ _build_message("1;33", message)
51
+ end
52
+ def white message=""
53
+ _build_message("1;37", message)
54
+ end
55
+ private
56
+ def _build_message(color, message)
57
+ "\033[#{color}m#{message}\033[0m"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ module AppTester
2
+ module Utils
3
+ module Strings
4
+ SUCCESS="[#{AppTester::Utils::Colours.green "SUCCESS"}]"
5
+ OK="[#{AppTester::Utils::Colours.blue "OK"}]"
6
+ DONE="[#{AppTester::Utils::Colours.green "OK"}]"
7
+ FAILED="[#{AppTester::Utils::Colours.red "FAILED"}]"
8
+ WARNING="[#{AppTester::Utils::Colours.yellow "WARNING"}]"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ module AppTester
2
+
3
+ load_libraries "utils/colors", "utils/strings"
4
+
5
+ # @abstract Helper utilities module
6
+ module Utils
7
+
8
+ extend self
9
+
10
+ include AppTester::Utils::Colours
11
+
12
+ # Convert a file to an array
13
+ #
14
+ # @param file [String] path to the file
15
+ #
16
+ # @return [Array] each entry on the array corresponds to each line on the file
17
+ def file_to_array file
18
+ lines = []
19
+ File.open(file, "r") do |infile|
20
+ while (line = infile.gets)
21
+ lines.push(line.gsub("\n", "").rstrip)
22
+ end
23
+ end
24
+ lines
25
+ end
26
+ end
27
+ end
data/lib/app-tester.rb ADDED
@@ -0,0 +1,168 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ # @abstract AppTester main module and namespace
5
+ module AppTester
6
+ VERSION = '0.0.1'
7
+
8
+ # @abstract AppTester main class
9
+ # @attr_reader [AppTester::Options] Options container. This will be shared across other classes
10
+ # @attr_reader [Hash] A hash of tests. Values take the format of AppTester::Test
11
+ class << self
12
+
13
+ attr_reader :options
14
+ attr_reader :tests
15
+
16
+ # Construct AppTester framework
17
+ #
18
+ # @yield [options] Gives the user the possibility to set generic options for the framework
19
+ # @yieldparam options [AppTester::Options] the options object
20
+ # @return [AppTester]
21
+ # @example Start AppTester handler
22
+ # apptester = AppTester.new do |options|
23
+ # options.add_environment :github => "https://github.com"
24
+ # options.add_environment :google => "https://google.com"
25
+ # options.default_environment = :google
26
+ # options.log_connection = true
27
+ # end
28
+ def new
29
+ @tests = {}
30
+ @options = AppTester::Options.new
31
+ yield @options if block_given?
32
+ self
33
+ end
34
+
35
+ # Create a new test object
36
+ #
37
+ # @param name [String] name for this test
38
+ #
39
+ # @yield [cmd_options, connection] code snippet that will be executed when AppTester::Test.run is issued
40
+ # @yieldparam cmd_options [AppTester::Parser] user selected options on command line
41
+ # @yieldparam connection [Faraday::Connection] the connection handler to the server selected on command line (or default fallback)
42
+ #
43
+ # @return [AppTester::Test] if the creation of this test was successfull with a block
44
+ # @return [NilClass] if the creation of this test was successfull with no block
45
+ #
46
+ # @raise [AppTester::Error::NameEmptyError] if name is empty
47
+ #
48
+ # @example Define a new test
49
+ # apptester.define_test "my test" do |cmd_options, connection|
50
+ # result = connection.get do |request|
51
+ # request.url "/"
52
+ # end
53
+ # AppTester::Checker.status result
54
+ #
55
+ # p AppTester::Utils.file_to_array cmd_options[:file] unless cmd_options[:file].nil?
56
+ # end
57
+ def define_test name=""
58
+ if name.empty?
59
+ raise AppTester::Error::NameEmptyError, "Attempted to define a test without a name"
60
+ else
61
+ if block_given?
62
+ @tests[name.to_sym] = AppTester::Test.new(name, @options) do |cmd_options, connection|
63
+ yield cmd_options, connection
64
+ end
65
+ else
66
+ @tests[name.to_sym] = nil
67
+ end
68
+ end
69
+ end
70
+
71
+ # Retrieve a test by name
72
+ #
73
+ # @param name [String] test to retrieve
74
+ #
75
+ # @return [AppTester::Test] found test
76
+ #
77
+ # @raise [AppTester::Error::TestNotFoundError] if no test was found
78
+ #
79
+ # @example Get a pre-defined test
80
+ # apptester = AppTester.new do |options|
81
+ # options.add_environment :github => "https://github.com"
82
+ # options.add_environment :google => "https://google.com"
83
+ # options.default_environment = :google
84
+ # end
85
+ #
86
+ # apptester.define_test "my test"
87
+ # my_test = apptester.get_test "my test"
88
+ def get_test name
89
+ raise AppTester::Error::TestNotFoundError, "Could not find test #{name}" unless @tests.keys.include?(name.to_sym)
90
+ @tests[name.to_sym]
91
+ end
92
+
93
+ # Defines command line options for a given test
94
+ #
95
+ # @param name [String] test name to which we want to define the command line options
96
+ #
97
+ # @return [AppTester::Test] the test for which we parsed the options
98
+ #
99
+ # @yield [options_parser] set the command line options for this test
100
+ # @yieldparam cmd_options [AppTester::Parser] command line options parser object
101
+ #
102
+ # @example Set options for a test
103
+ # apptester = AppTester.new do |options|
104
+ # options.add_environment :github => "https://github.com"
105
+ # options.add_environment :google => "https://google.com"
106
+ # options.default_environment = :google
107
+ # end
108
+ #
109
+ # apptester.define_test "my test"
110
+ #
111
+ # apptester.set_options_for "my test" do |options_parser|
112
+ # options_parser.set_option(:file, "-f", "--file FILE", "File to load")
113
+ # options_parser.mandatory_options = 0
114
+ # end
115
+ def set_options_for name
116
+ test = get_test name
117
+ yield test.parser
118
+ test
119
+ end
120
+
121
+ # Run a test
122
+ #
123
+ # @param name [String] test name that we want to run
124
+ # @param arguments [Array] overwrite ARGV array with a custom one, useful for unit tests
125
+ #
126
+ # @return [AppTester::Test] the test that we're running
127
+ #
128
+ # @raise [AppTester::Error::TestNotFoundError] if no test was found
129
+ # @raise [OptionParser::MissingArgument] if there's a argument missing from a missmatch in the number of arguments given and mandatory_options on set_options_for method
130
+ # @raise [Faraday::Error::ConnectionFailed] if there was a problem connecting to the selected server
131
+ #
132
+ # @example Run a test
133
+ # apptester = AppTester.new do |options|
134
+ # options.add_environment :github => "https://github.com"
135
+ # options.add_environment :google => "https://google.com"
136
+ # options.default_environment = :google
137
+ # end
138
+ # apptester.define_test "my test" do |cmd_options, connection|
139
+ # result = connection.get do |request|
140
+ # request.url "/"
141
+ # end
142
+ # AppTester::Checker.status result
143
+ #
144
+ # p AppTester::Utils.file_to_array cmd_options[:file] unless cmd_options[:file].nil?
145
+ # end
146
+ #
147
+ # my_test = apptester.run_test
148
+ def run_test name, arguments=ARGV
149
+ the_test = get_test(name)
150
+ the_test.run(arguments)
151
+ the_test
152
+ end
153
+
154
+ # Load libraries to be used under this namespace
155
+ #
156
+ # @param libs [String] list of libraries to load
157
+ #
158
+ # @return [NilClass]
159
+ def load_libraries *libs
160
+ libs.each do |lib|
161
+ require_relative "app-tester/#{lib}"
162
+ end
163
+ end
164
+ alias load_library load_libraries
165
+ end
166
+
167
+ load_libraries "core", "utils", "options", "test", "parser", "connection", "exceptions", "timer", "checker"
168
+ end
@@ -0,0 +1,285 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require 'tempfile'
3
+
4
+ # Time to add your specs!
5
+ # http://rspec.info/
6
+ describe "App Tester framework" do
7
+
8
+ it "should initialize" do
9
+ # violated "Be sure to write your specs"
10
+ apptester = AppTester.new
11
+ apptester.should be_a(Module)
12
+ apptester.should respond_to(:options)
13
+ end
14
+
15
+ it "should set options" do
16
+ apptester = start_app_tester
17
+
18
+ apptester.options.environments.should be_a(Hash)
19
+ apptester.options.environments.size.should eq(3)
20
+ apptester.options.environments[:production].should eq("localhost://production")
21
+ apptester.options.environments[:staging].should eq("localhost://staging")
22
+ apptester.options.environments[:development].should eq("localhost://development")
23
+ end
24
+
25
+ it "should return help when asked for it" do
26
+ apptester = start_app_tester
27
+
28
+ apptester.define_test "my test" do |options, connection|
29
+ # blergh!
30
+ end
31
+
32
+ lambda { apptester.run_test("my test", ["--help"]) }.should raise_error SystemExit
33
+ end
34
+
35
+ it "should define a test and run it" do
36
+ apptester = start_app_tester
37
+
38
+ mock_arguments "-s" => "production"
39
+
40
+ apptester.define_test("test 1") do |options, connection|
41
+ options.should be_a(Hash)
42
+ connection.should be_a(Faraday::Connection)
43
+ end
44
+ apptester.define_test("test 2") do |options, connection|
45
+ options.should be_a(Hash)
46
+ connection.should be_a(Faraday::Connection)
47
+ end
48
+ apptester.tests.size.should eq(2)
49
+ apptester.run_test("test 1").should be_a(AppTester::Test)
50
+ apptester.run_test("test 2").should be_a(AppTester::Test)
51
+ end
52
+
53
+ it "should define a test without a default environment" do
54
+ apptester = start_app_tester
55
+
56
+ apptester.define_test "my test" do |options, connection|
57
+ options[:server].should eq("localhost://production")
58
+ end
59
+
60
+ apptester.run_test("my test", [])
61
+ end
62
+
63
+ it "should define a test with a default environment" do
64
+ apptester = start_app_tester nil, :staging
65
+
66
+ apptester.define_test "my test" do |options, connection|
67
+ options[:server].should eq("localhost://staging")
68
+ end
69
+
70
+ apptester.run_test("my test", [])
71
+ end
72
+
73
+ it "should define a test, set custom options and run" do
74
+ apptester = start_app_tester
75
+
76
+ apptester.define_test "my test" do |options, connection|
77
+ options.should be_a(Hash)
78
+ connection.should be_a(Faraday::Connection)
79
+ options.size.should be(2)
80
+ options[:server].should_not be_empty
81
+ options[:smiles_file].should_not be_empty
82
+ end
83
+
84
+ apptester.set_options_for "my test" do |test_options|
85
+ test_options.set_option(:smiles_file, "-f", "--smiles-file FILE", "File containing SMILES for query (one per line)")
86
+ end
87
+
88
+ mocked_arguments = mock_arguments "-s" => "development", "-f" => "../../file.txt"
89
+
90
+ apptester.run_test("my test", mocked_arguments)
91
+ end
92
+
93
+ it "should define a test, set custom options, define number mandatory options and run" do
94
+ apptester = start_app_tester
95
+
96
+ apptester.define_test "my test" do |options, connection|
97
+
98
+ end
99
+
100
+ apptester.set_options_for "my test" do |test_options|
101
+ test_options.set_option(:smiles_file, "-f", "--smiles-file FILE", "File containing SMILES for query (one per line)")
102
+ test_options.mandatory_options = 1
103
+ end
104
+
105
+ mocked_arguments = mock_arguments "-s" => "development"
106
+
107
+ lambda { apptester.run_test("my test", mocked_arguments) }.should raise_error OptionParser::MissingArgument
108
+ end
109
+
110
+ it "should create a connection" do
111
+ apptester = start_app_tester :production => "http://www.google.com"
112
+
113
+ apptester.define_test "my test" do |options, connection|
114
+ connection.should be_a(Faraday::Connection)
115
+ end
116
+
117
+ mocked_arguments = mock_arguments "-s" => "production"
118
+
119
+ apptester.run_test("my test", mocked_arguments)
120
+ end
121
+
122
+ it "should fetch contents of a connection" do
123
+ apptester = start_app_tester :production => "https://github.com"
124
+
125
+ apptester.define_test "my test" do |options, connection|
126
+ response = connection.get do |req|
127
+ req.url "/"
128
+ end
129
+ response.status.should eq(200)
130
+ response.body.should include("github")
131
+ end
132
+
133
+ mocked_arguments = mock_arguments "-s" => "production"
134
+
135
+ apptester.run_test("my test", mocked_arguments)
136
+ end
137
+
138
+ it "should return exception on connection failed" do
139
+ apptester = start_app_tester :production => "http://aoisjdioasjdioasjod"
140
+
141
+ apptester.define_test "my test" do |options, connection|
142
+ begin
143
+ response = connection.get do |req|
144
+ req.url "/"
145
+ end
146
+ rescue Exception => e
147
+ e.should be_a(Faraday::Error::ConnectionFailed)
148
+ end
149
+ end
150
+
151
+ mocked_arguments = mock_arguments "-s" => "production"
152
+
153
+ apptester.run_test("my test", mocked_arguments)
154
+ end
155
+
156
+ it "should check status" do
157
+ apptester = start_app_tester :production => "https://github.com"
158
+
159
+ apptester.define_test "my test" do |options, connection|
160
+ response = connection.get do |req|
161
+ req.url "/"
162
+ end
163
+ AppTester::Checker.status response
164
+ end
165
+
166
+ mocked_arguments = mock_arguments "-s" => "production"
167
+
168
+ read_stdout do
169
+ apptester.run_test("my test", mocked_arguments)
170
+ end.should include("[\033[0;32mSUCCESS\033[0m] got status")
171
+ end
172
+
173
+ it "should log connections if asked for" do
174
+ apptester = start_app_tester({ :production => "https://github.com" }, nil, true)
175
+
176
+ apptester.define_test "my test" do |options, connection|
177
+ response = connection.get do |req|
178
+ req.url "/"
179
+ end
180
+ end
181
+
182
+ mocked_arguments = mock_arguments "-s" => "production"
183
+
184
+ read_stdout do
185
+ apptester.run_test("my test", mocked_arguments)
186
+ end.should include("DEBUG")
187
+ end
188
+
189
+ it "should output colors correctly" do
190
+ AppTester::Utils::Colours.black("hello").should eq("\033[0;30mhello\033[0m")
191
+ AppTester::Utils::Colours.blue("hello").should eq("\033[0;34mhello\033[0m")
192
+ AppTester::Utils::Colours.green("hello").should eq("\033[0;32mhello\033[0m")
193
+ AppTester::Utils::Colours.cyan("hello").should eq("\033[0;36mhello\033[0m")
194
+ AppTester::Utils::Colours.red("hello").should eq("\033[0;31mhello\033[0m")
195
+ AppTester::Utils::Colours.purple("hello").should eq("\033[0;35mhello\033[0m")
196
+ AppTester::Utils::Colours.brown("hello").should eq("\033[0;33mhello\033[0m")
197
+ AppTester::Utils::Colours.light_gray("hello").should eq("\033[0;37mhello\033[0m")
198
+ AppTester::Utils::Colours.dark_gray("hello").should eq("\033[1;30mhello\033[0m")
199
+ AppTester::Utils::Colours.light_blue("hello").should eq("\033[1;34mhello\033[0m")
200
+ AppTester::Utils::Colours.light_green("hello").should eq("\033[1;32mhello\033[0m")
201
+ AppTester::Utils::Colours.light_cyan("hello").should eq("\033[1;36mhello\033[0m")
202
+ AppTester::Utils::Colours.light_red("hello").should eq("\033[1;31mhello\033[0m")
203
+ AppTester::Utils::Colours.light_purple("hello").should eq("\033[1;35mhello\033[0m")
204
+ AppTester::Utils::Colours.yellow("hello").should eq("\033[1;33mhello\033[0m")
205
+ AppTester::Utils::Colours.white("hello").should eq("\033[1;37mhello\033[0m")
206
+ end
207
+
208
+ it "should throw exception on no name test" do
209
+ apptester = start_app_tester
210
+ lambda { apptester.define_test }.should raise_exception(AppTester::Error::NameEmptyError)
211
+ end
212
+
213
+ it "should throw exception on test not found" do
214
+ apptester = start_app_tester
215
+ apptester.define_test "hello"
216
+ lambda { apptester.get_test "bye" }.should raise_exception(AppTester::Error::TestNotFoundError)
217
+ end
218
+
219
+ it "should time the execution" do
220
+ apptester = start_app_tester
221
+
222
+ apptester.define_test "my test" do |options, connection|
223
+ AppTester::Timer.new("test timer") do
224
+ sleep 1
225
+ end
226
+ end
227
+
228
+ read_stdout do
229
+ apptester.run_test("my test")
230
+ end.should include("Time elapsed to test timer, 100")
231
+ end
232
+
233
+ it "should time the execution with threshold" do
234
+ apptester = start_app_tester
235
+
236
+ apptester.define_test "my test 400 threshold" do |options, connection|
237
+ AppTester::Timer.new("test timer", 400) do
238
+ sleep 0.5
239
+ end
240
+ end
241
+
242
+ apptester.define_test "my test 600 threshold" do |options, connection|
243
+ AppTester::Timer.new("test timer", 600) do
244
+ sleep 0.5
245
+ end
246
+ end
247
+
248
+ output = read_stdout do
249
+ apptester.run_test("my test 400 threshold")
250
+ end
251
+ output.should include("WARNING")
252
+ output.should include("Time elapsed to test timer, 50")
253
+ output.should include("threshold: 400")
254
+
255
+ output = read_stdout do
256
+ apptester.run_test("my test 600 threshold")
257
+ end
258
+ output.should_not include("WARNING")
259
+ output.should include("Time elapsed to test timer, 50")
260
+ output.should include("threshold: 600")
261
+ end
262
+
263
+ def mock_arguments hash={ }
264
+ hash.flatten
265
+ end
266
+
267
+ def start_app_tester(environments=nil, default_environment=nil, log_connections=nil)
268
+ AppTester.new do |options|
269
+ (environments || { :production => "localhost://production", :staging => "localhost://staging", :development => "localhost://development" }).each do |k, v|
270
+ options.add_environment k => v
271
+ end
272
+ options.default_environment = default_environment unless default_environment.nil?
273
+ options.log_connections = log_connections unless log_connections.nil?
274
+ end
275
+ end
276
+
277
+ def read_stdout
278
+ results = Tempfile.new('a').path
279
+ a = STDOUT.dup
280
+ STDOUT.reopen(results, 'w')
281
+ yield
282
+ STDOUT.reopen(a)
283
+ File.read(results)
284
+ end
285
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'rspec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ gem 'rspec'
6
+ require 'rspec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'app-tester'
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestAppTester < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/app-tester'
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: app-tester
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jose P. Airosa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.7.5
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.7.5
30
+ - !ruby/object:Gem::Dependency
31
+ name: faraday
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.8.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.8.4
46
+ description: Command-line Framework to run functional tests against a web application
47
+ (API, Website, etc)
48
+ email: me@joseairosa.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/app-tester/checker.rb
54
+ - lib/app-tester/connection.rb
55
+ - lib/app-tester/core.rb
56
+ - lib/app-tester/exceptions.rb
57
+ - lib/app-tester/options.rb
58
+ - lib/app-tester/parser.rb
59
+ - lib/app-tester/test.rb
60
+ - lib/app-tester/timer.rb
61
+ - lib/app-tester/utils/colors.rb
62
+ - lib/app-tester/utils/strings.rb
63
+ - lib/app-tester/utils.rb
64
+ - lib/app-tester.rb
65
+ - README.md
66
+ - Rakefile
67
+ - spec/app-tester_spec.rb
68
+ - spec/spec.opts
69
+ - spec/spec_helper.rb
70
+ - test/test_app-tester.rb
71
+ - test/test_helper.rb
72
+ homepage: https://github.com/joseairosa/app-tester
73
+ licenses:
74
+ - MIT
75
+ post_install_message: ! "\e[0;32mThanks for installing! You're awesome ^_^\e[0m"
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project: app-tester
93
+ rubygems_version: 1.8.24
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: Application Tester Framework
97
+ test_files:
98
+ - spec/app-tester_spec.rb