app-tester 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.
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