tddium-preview 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,49 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ spec_test_data
18
+ tmp
19
+ results
20
+ nbproject
21
+ .rvmrc
22
+ .tddium
23
+
24
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
25
+ #
26
+ # * Create a file at ~/.gitignore
27
+ # * Include files you want ignored
28
+ # * Run: git config --global core.excludesfile ~/.gitignore
29
+ #
30
+ # After doing this, these files will be ignored in all your git projects,
31
+ # saving you from having to 'pollute' every project you touch with them
32
+ #
33
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
34
+ #
35
+ # For MacOS:
36
+ #
37
+ #.DS_Store
38
+ #
39
+ # For TextMate
40
+ #*.tmproj
41
+ #tmtags
42
+ #
43
+ # For emacs:
44
+ #*~
45
+ #\#*
46
+ #.\#*
47
+ #
48
+ # For vim:
49
+ *.swp
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ v0.0.1 - Initial Version
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tddium.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,2 @@
1
+ Copyright (c) 2010 Jay Moorthi All Rights Reserved.
2
+
data/README.rdoc ADDED
@@ -0,0 +1,62 @@
1
+ = tddium
2
+
3
+ tddium takes the pain out of running Selenium testing in cloud.
4
+
5
+ It automatically starts private Amazon EC2 Instances, runs your test,
6
+ collect results, and cleans up the EC2 resources it used so you only pay for
7
+ what you use.
8
+
9
+ == Getting Started
10
+
11
+ 1. Sign up for an EC2 account, by going here:
12
+
13
+ https://aws-portal.amazon.com/gp/aws/developer/registration/index.html
14
+
15
+ Note that if you have a personal Amazon account, you'll want to make a new one
16
+ for Amazon Web Services.
17
+
18
+ The registration process generates a variety of certificates and keys. Please
19
+ keep track of them.
20
+
21
+ 2. Note your AWS Access Key and AWS Secret. You can find them by the following
22
+ steps:
23
+
24
+ - go to the AWS Management Console
25
+ - click on the "Account" link in the upper navigation menu
26
+ - click on "Security Credentials"
27
+ - scroll down to the first section "Access Credentials"
28
+ - the Access Key is a 20-character alphabetic string. The Secret is hidden. Click the 'show' link to reveal it.
29
+
30
+ 3. In the AWS Management Console, create a selenium-grid security group, and
31
+ create rules for:
32
+
33
+ * allow dest port 4444 (Selenium-Grid)
34
+ * allow dest port 5900 (Windows Remote Desktop)
35
+ * allow http
36
+ * allow https
37
+ * allow vnc
38
+ * allow ssh
39
+
40
+ 4. In the AWS Management Console, create a keypair called sg-keypair.
41
+
42
+ 3. Subscribe to tddium:
43
+
44
+ Subscribe your Amazon EC2 account to tddium here:
45
+
46
+ https://aws-portal.amazon.com/gp/aws/user/subscription/index.html?ie=UTF8&offeringCode=FA429DE5
47
+
48
+ 4. Start using tddium:
49
+
50
+ <tt>$ tddium config:init</tt>
51
+
52
+ # Asks you for the AWS Access Key and AWS Secret
53
+
54
+ <tt>$ tddium test:sequential</tt>
55
+
56
+ # Starts an EC2 Instance, sets SELENIUM_RC_HOST to it, and runs **/*_spec.rb in sequence
57
+
58
+ == Copyright
59
+
60
+ Copyright (c) 2010 Jay Moorthi. See LICENSE.txt for
61
+ further details.
62
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/bin/tddium ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+ Copyright (c) 2010 tddium.com All Rights Reserved
5
+ =end
6
+
7
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
8
+ require "tddium"
9
+ Tddium.start
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ module Tddium
2
+ VERSION = "0.0.1"
3
+ end
data/lib/tddium.rb ADDED
@@ -0,0 +1,229 @@
1
+ =begin
2
+ Copyright (c) 2010 tddium.com All Rights Reserved
3
+ =end
4
+
5
+ require "rubygems"
6
+ require "thor"
7
+ require "httparty"
8
+ require "json"
9
+
10
+ # Usage:
11
+ #
12
+ # tddium suite # Register the suite for this rails app, or manage its settings
13
+ # tddium spec # Run the test suite
14
+ # tddium status # Display information about this suite, and any open dev sessions
15
+ #
16
+ # tddium login # Log your unix user in to a tddium account
17
+ # tddium logout # Log out
18
+ #
19
+ # tddium account # View/Manage account information
20
+ #
21
+ # tddium dev # Enter "dev" mode, for single-test quick-turnaround debugging.
22
+ # tddium stopdev # Leave "dev" mode.
23
+ #
24
+ # tddium clean # Clean up test results, especially large objects like videos
25
+ #
26
+ # tddium help # Print this usage message
27
+
28
+ class Tddium < Thor
29
+ API_HOST = "https://api.tddium.com"
30
+ API_VERSION = "1"
31
+ API_KEY_HEADER = "X-tddium-api-key"
32
+ SUITES_PATH = "suites"
33
+ SESSIONS_PATH = "sessions"
34
+ TEST_EXECUTIONS_PATH = "test_executions"
35
+ REGISTER_TEST_EXECUTIONS_PATH = "#{TEST_EXECUTIONS_PATH}/register"
36
+ START_TEST_EXECUTIONS_PATH = "#{TEST_EXECUTIONS_PATH}/start"
37
+ REPORT_TEST_EXECUTIONS_PATH = "#{TEST_EXECUTIONS_PATH}/report"
38
+ GIT_REMOTE_NAME = "tddium"
39
+ GIT_REMOTE_SCHEME = "ssh"
40
+ GIT_REMOTE_USER = "git"
41
+ GIT_REMOTE_ABSOLUTE_PATH = "/home/git/repo"
42
+ SLEEP_TIME_BETWEEN_POLLS = 2
43
+ TERMINATE_PROCESS_INSTRUCTIONS = "Ctrl-C to terminate the process"
44
+ INTERRUPT_TEXT = "Interrupted"
45
+ NOT_INITIALIZED_ERROR = "tddium must be initialized. Try 'tddium login'"
46
+ INVALID_TDDIUM_FILE = ".tddium config file is corrupt. Try 'tddium login'"
47
+
48
+ desc "suite", "Register the suite for this rails app, or manage its settings"
49
+ method_option :ssh_key, :type => :string, :default => nil
50
+ method_option :test_pattern, :type => :string, :default => nil
51
+ method_option :name, :type => :string, :default => nil
52
+ def suite
53
+ return unless git_repo? && tddium_settings
54
+
55
+ # Inputs for API call
56
+ params = {}
57
+
58
+ default_ssh_file = "~/.ssh/id_rsa.pub"
59
+ ssh_file = options[:ssh_key] || ask("Enter your ssh key or press 'Return'. Using #{default_ssh_file} by default:")
60
+ ssh_file = default_ssh_file if ssh_file.empty?
61
+ params[:ssh_key] = File.open(File.expand_path(ssh_file)) {|file| file.read}
62
+
63
+ default_test_pattern = "**/*_spec.rb"
64
+ test_pattern = options[:test_pattern] || ask("Enter a test pattern or press 'Return'. Using #{default_test_pattern} by default:")
65
+ params[:test_pattern] = test_pattern.empty? ? default_test_pattern : test_pattern
66
+
67
+ default_suite_name = "#{File.basename(Dir.pwd)}/#{current_git_branch}"
68
+ suite_name = options[:name] || ask("Enter a suite name or press 'Return'. Using '#{default_suite_name}' by default:")
69
+ params[:suite_name] = suite_name.empty? ? default_suite_name : suite_name
70
+
71
+ params[:ruby_version] = `ruby -v`.match(/^ruby ([\d\.]+)/)[1]
72
+
73
+ call_api(:post, SUITES_PATH, {:suite => params}) do |api_response|
74
+ # Manage git
75
+ `git remote rm #{GIT_REMOTE_NAME}`
76
+ `git remote add #{GIT_REMOTE_NAME} #{tddium_git_repo_uri(params[:suite_name])}`
77
+ git_push
78
+
79
+ # Save the created suite
80
+ branches = tddium_settings["branches"] || {}
81
+ branches.merge!({current_git_branch => api_response["suite"]["id"]})
82
+ File.open(".tddium", "w") do |file|
83
+ file.write(tddium_settings.merge({:branches => branches}).to_json)
84
+ end
85
+ end
86
+ end
87
+
88
+ desc "spec", "Run the test suite"
89
+ def spec
90
+ start_time = Time.now
91
+
92
+ return unless git_repo? && tddium_settings
93
+ suite_id = tddium_settings["branches"][current_git_branch]
94
+
95
+ # Push the latest code to git
96
+ git_push
97
+
98
+ # Call the API to get the suite and its tests
99
+ call_api(:get, "#{SUITES_PATH}/#{suite_id}") do |api_response|
100
+ test_pattern = api_response["suite"]["test_pattern"]
101
+ test_files = Dir.glob(test_pattern).collect {|file_path| {:test_name => file_path}}
102
+
103
+ # Create a session
104
+ call_api(:post, SESSIONS_PATH) do |api_response|
105
+ session_id = api_response["session"]["id"]
106
+
107
+ # Call the API to register the tests
108
+ call_api(:post, "#{SESSIONS_PATH}/#{session_id}/#{REGISTER_TEST_EXECUTIONS_PATH}", {:suite_id => suite_id, :tests => test_files}) do |api_response|
109
+ # Start the tests
110
+ call_api(:post, "#{SESSIONS_PATH}/#{session_id}/#{START_TEST_EXECUTIONS_PATH}") do |api_response|
111
+ tests_not_finished_yet = true
112
+ finished_tests = {}
113
+ test_statuses = Hash.new(0)
114
+ api_call_successful = true
115
+ say TERMINATE_PROCESS_INSTRUCTIONS
116
+ while tests_not_finished_yet && api_call_successful do
117
+ # Poll the API to check the status
118
+ api_call_successful = call_api(:get, "#{SESSIONS_PATH}/#{session_id}/#{TEST_EXECUTIONS_PATH}") do |api_response|
119
+ Signal.trap(:INT) do
120
+ say INTERRUPT_TEXT
121
+ tests_not_finished_yet = false
122
+ end
123
+ # Print out the progress of running tests
124
+ api_response["tests"].each do |test_name, result_params|
125
+ test_status = result_params["status"]
126
+ if result_params["end_time"] && !finished_tests[test_name]
127
+ message = case test_status
128
+ when "passed" then [".", :green]
129
+ when "failed" then ["F", :red]
130
+ when "error" then ["E"]
131
+ when "pending" then ["*", :yellow]
132
+ end
133
+ finished_tests[test_name] = test_status
134
+ test_statuses[test_status] += 1
135
+ say message[0], message[1]
136
+ end
137
+ end
138
+
139
+ # If all tests finished, exit the loop else sleep
140
+ finished_tests.size == api_response["tests"].size ? tests_not_finished_yet = false : sleep(SLEEP_TIME_BETWEEN_POLLS)
141
+ end
142
+ end
143
+
144
+ # Print out the result
145
+ say "Finished in #{Time.now - start_time} seconds"
146
+ say "#{finished_tests.size} examples, #{test_statuses["failed"]} failures, #{test_statuses["error"]} errors, #{test_statuses["pending"]} pending"
147
+ say "You can check out the test report details at #{api_response["report"]}"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ def call_api(method, api_path, params = {}, &block)
157
+ headers = { API_KEY_HEADER => tddium_settings(false)["api_key"] } if tddium_settings(false) && tddium_settings(false)["api_key"]
158
+ done = false
159
+ tries = 0
160
+ while tries < 5 && !done
161
+ begin
162
+ http = HTTParty.send(method, tddium_uri(api_path), :body => params, :headers => headers)
163
+ done = true
164
+ rescue Timeout::Error
165
+ ensure
166
+ tries += 5
167
+ end
168
+ end
169
+
170
+ response = JSON.parse(http.body) rescue {}
171
+
172
+ if http.success?
173
+ if response["status"] == 0
174
+ yield response
175
+ else
176
+ message = "An error occured: #{response["explanation"]}"
177
+ end
178
+ else
179
+ message = "An error occured: #{http.response.header.msg}"
180
+ message << " #{response["explanation"]}" if response["status"].to_i > 0
181
+ end
182
+ say message if message
183
+ message.nil?
184
+ end
185
+
186
+ def git_push
187
+ `git push #{GIT_REMOTE_NAME} #{current_git_branch}`
188
+ end
189
+
190
+ def tddium_uri(path, api_version = API_VERSION)
191
+ URI.join(API_HOST, "#{api_version}/#{path}").to_s
192
+ end
193
+
194
+ def tddium_git_repo_uri(suite_name)
195
+ repo_name = suite_name.split("/").first
196
+ git_uri = URI.parse(API_HOST)
197
+ git_uri.scheme = GIT_REMOTE_SCHEME
198
+ git_uri.userinfo = GIT_REMOTE_USER
199
+ git_uri.path = "#{GIT_REMOTE_ABSOLUTE_PATH}/#{repo_name}"
200
+ git_uri.to_s
201
+ end
202
+
203
+ def current_git_branch
204
+ @current_git_branch ||= File.basename(`git symbolic-ref HEAD`.gsub("\n", ""))
205
+ end
206
+
207
+ def tddium_settings(fail_with_message = true)
208
+ unless @tddium_settings
209
+ if File.exists?(".tddium")
210
+ tddium_config = File.open(".tddium") do |file|
211
+ file.read
212
+ end
213
+ @tddium_settings = JSON.parse(tddium_config) rescue nil
214
+ say INVALID_TDDIUM_FILE if @tddium_settings.nil? && fail_with_message
215
+ else
216
+ say NOT_INITIALIZED_ERROR if fail_with_message
217
+ end
218
+ end
219
+ @tddium_settings
220
+ end
221
+
222
+ def git_repo?
223
+ unless File.exists?(".git")
224
+ message = "git repo must be initialized. Try 'git init'."
225
+ say message
226
+ end
227
+ message.nil?
228
+ end
229
+ end
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 04 Mar 2011 05:58:52 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ ETag: "6f1f75f9653abfa85b807ea9a90c91dc"
6
+ Cache-Control: max-age=0, private, must-revalidate
7
+ X-UA-Compatible: IE=Edge
8
+ X-Runtime: 0.051654
9
+ Status: 200
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"suite":{"created_at":"2011-03-04T04:21:00Z","id":24,"ruby_version":"1.8.7","ssh_key":"ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3YO0EJKUJsdrrqptMqXWhDLetOIqwnhSw3NDEXDEs699JjIx7y7dEYVISWnmW63fdlD5piKfByhbn/dL1T9oPfAV+o56tFZMBHI4UdZu9cEWqnbEZDnCzoSj7K3M5m7pQmG9K9MHjlAnPNL1oD8hykBQOIkR0hzG6TvIte6arkhvDGEcm3SoS2yykIRY8s6t/3u97FmlIoUjJnsMmx6GP9aO7YeZi70gySeVJQW4xvhb+qVIyCvIknXtZcmSenmy0fStzz8UX6HLczX0/U9MvAMpPi97gT6CsiGAkVmUTdiAXDktqQ1OO+GiadqaNFnQlt9Kb/wVAV56tAqqvSNjlQ== dwilkie@gmail.com\n","suite_name":"tddium/demo","test_pattern":"**/*_spec.rb","updated_at":"2011-03-04T04:21:00Z","user_id":null},"status":0}
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 04 Mar 2011 09:59:03 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ ETag: "e1ccfca6b97460395252d127788c81b8"
6
+ Cache-Control: max-age=0, private, must-revalidate
7
+ X-UA-Compatible: IE=Edge
8
+ X-Runtime: 0.167928
9
+ Status: 200
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"status":0,"report":"http://api.tddium.com/1/sessions/7/test_executions/report","tests":{"spec/cat_spec.rb":{"end_time":"2011-03-04T07:05:12Z","id":1,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:05:06Z","status":"passed","test_script_id":24,"usage":null},"spec/dog_spec.rb":{"end_time":"2011-03-04T07:06:12Z","id":2,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:06:06Z","status":"failed","test_script_id":25,"usage":null},"spec/mouse_spec.rb":{"end_time":"2011-03-04T07:07:06Z","id":3,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:07:06Z","status":"pending","test_script_id":26,"usage":null},"spec/pig_spec.rb":{"end_time":null,"id":4,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:08:06Z","status":"started","test_script_id":27,"usage":null}}}
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 04 Mar 2011 09:59:03 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ ETag: "e1ccfca6b97460395252d127788c81b8"
6
+ Cache-Control: max-age=0, private, must-revalidate
7
+ X-UA-Compatible: IE=Edge
8
+ X-Runtime: 0.167928
9
+ Status: 200
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"status":0,"report":"http://api.tddium.com/1/sessions/7/test_executions/report","tests":{"spec/cat_spec.rb":{"end_time":"2011-03-04T07:05:12Z","id":1,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:05:06Z","status":"passed","test_script_id":24,"usage":null},"spec/dog_spec.rb":{"end_time":"2011-03-04T07:06:12Z","id":2,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:06:06Z","status":"failed","test_script_id":25,"usage":null},"spec/mouse_spec.rb":{"end_time":"2011-03-04T07:07:06Z","id":3,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:07:06Z","status":"pending","test_script_id":26,"usage":null},"spec/pig_spec.rb":{"end_time":"2011-03-04T07:07:06Z","id":4,"instance_id":null,"result":null,"session_id":7,"start_time":"2011-03-04T07:08:06Z","status":"error","test_script_id":27,"usage":null}}}
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 04 Mar 2011 07:05:51 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ ETag: "e0faa4dfc5cc0b52cf191a834f9916c2"
6
+ Cache-Control: max-age=0, private, must-revalidate
7
+ X-UA-Compatible: IE=Edge
8
+ X-Runtime: 0.120408
9
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlOWFjNmU1MGZlMzBlYmIzZThjMTc1YjgzZjYxOWEwNGI%3D--0b52bea072b1a268dd9cbd74cc9d0e07b98f7164; path=/; HttpOnly
10
+ Status: 200
11
+ Transfer-Encoding: chunked
12
+ Content-Type: application/json; charset=utf-8
13
+
14
+ {"added":0,"errors":0,"existing":1,"status":0}
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 04 Mar 2011 06:52:49 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ ETag: "c0ef16e8f392ddfc29848e2dd3818743"
6
+ Cache-Control: max-age=0, private, must-revalidate
7
+ X-UA-Compatible: IE=Edge
8
+ X-Runtime: 0.078775
9
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlYzA5MjAzMTU5ZGZlYTZmYjljNzczNWFkNmMwYTQ2ZDk%3D--cd9dca3bf0a93adac3a9ac5e1ea60bd2cd66cba4; path=/; HttpOnly
10
+ Status: 200
11
+ Transfer-Encoding: chunked
12
+ Content-Type: application/json; charset=utf-8
13
+
14
+ {"added":0,"errors":3,"existing":0,"explanation":["Unrecognized script: cat_spec.rb","Unrecognized script: dog_spec.rb","Unrecognized script: mouse_spec.rb"],"status":1}
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 201 Created
2
+ Date: Fri, 04 Mar 2011 06:09:57 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ Cache-Control: no-cache
6
+ X-UA-Compatible: IE=Edge
7
+ X-Runtime: 0.087735
8
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlYTZiYzQ5MzgzZDBhZmIxZWVjMzQ2ZjNiYmU3NmE2YTM%3D--82fb82e23ef118be5afd44f6634de96fc4425eb9; path=/; HttpOnly
9
+ Status: 201
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"session":{"created_at":"2011-03-04T06:09:57Z","id":7,"updated_at":"2011-03-04T06:09:57Z","user_id":null},"status":0}
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 04 Mar 2011 09:58:45 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ ETag: "0b921ebe813ca52c08b8f852cb81c0ed"
6
+ Cache-Control: max-age=0, private, must-revalidate
7
+ X-UA-Compatible: IE=Edge
8
+ X-Runtime: 0.146704
9
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlYzk2OTZkYjI4OWViNTE4MDIxMDg1OTIyNmY1NTVjZTA%3D--f05ccc3fd61da38d791ad69dc635c9bbb1c0eeac; path=/; HttpOnly
10
+ Status: 200
11
+ Transfer-Encoding: chunked
12
+ Content-Type: application/json; charset=utf-8
13
+
14
+ {"started":1,"status":0}
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 201 Created
2
+ Date: Thu, 03 Mar 2011 10:25:28 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ Cache-Control: no-cache
6
+ X-UA-Compatible: IE=Edge
7
+ X-Runtime: 0.096863
8
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlYjk0YTMzNmZmNzQ1NTI1NDk5YmE2NTc4Y2IxNTYxNGU%3D--d841305e17bd1b770b2b99ae74a03bc7aa5eddd5; path=/; HttpOnly
9
+ Status: 201
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"suite":{"created_at":"2011-03-03T10:25:28Z","id":19,"ruby_version":"1.9.2","ssh_key":"ssh-rsa blah","suite_name":"tddium/demo","test_pattern":"**/*_spec.rb","updated_at":"2011-03-03T10:25:28Z","user_id":null},"status":0}
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 269 Duplicated
2
+ Date: Thu, 03 Mar 2011 10:00:32 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ Cache-Control: no-cache
6
+ X-UA-Compatible: IE=Edge
7
+ X-Runtime: 0.045332
8
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlOGZiMTgxZjM0ZGIwMmJlMzI2ZWQwMmFkYzUwZGEzZDU%3D--287be8a7de3c8535fc4d958d2fc036110e64e5b6; path=/; HttpOnly
9
+ Status: 269
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"status":1,"explanation":"{:suite_name=>[\"has already been taken\"]}"}
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 409 Conflict
2
+ Date: Thu, 03 Mar 2011 10:00:32 GMT
3
+ Server: Apache
4
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.3
5
+ Cache-Control: no-cache
6
+ X-UA-Compatible: IE=Edge
7
+ X-Runtime: 0.045332
8
+ Set-Cookie: _tddium_site_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlOGZiMTgxZjM0ZGIwMmJlMzI2ZWQwMmFkYzUwZGEzZDU%3D--287be8a7de3c8535fc4d958d2fc036110e64e5b6; path=/; HttpOnly
9
+ Status: 409
10
+ Transfer-Encoding: chunked
11
+ Content-Type: application/json; charset=utf-8
12
+
13
+ {"status":1,"explanation":"{:suite_name=>[\"has already been taken\"]}"}
@@ -0,0 +1,9 @@
1
+ require "tddium"
2
+ require "fakeweb"
3
+ require "rack/test"
4
+ require "fakefs/spec_helpers"
5
+ FakeWeb.allow_net_connect = false
6
+
7
+ def fixture_path(fixture_name)
8
+ File.join File.dirname(__FILE__), "fixtures", fixture_name
9
+ end
@@ -0,0 +1,489 @@
1
+ require 'spec_helper'
2
+
3
+ # TODO: Test what happens if an error occurs in the POST and GET requests
4
+ describe Tddium do
5
+ include FakeFS::SpecHelpers
6
+
7
+ SSH_KEY_PROMPT = "Enter your ssh key or press 'Return'. Using ~/.ssh/id_rsa.pub by default:"
8
+ TEST_PATTERN_PROMPT = "Enter a test pattern or press 'Return'. Using **/*_spec.rb by default:"
9
+ DEFAULT_APP_NAME = "tddelicious"
10
+ DEFAULT_BRANCH_NAME = "test"
11
+ DEFAULT_SUITE_ID = "66"
12
+ DEFAULT_API_KEY = "afb12412bdafe124124asfasfabebafeabwbawf1312342erbfasbb"
13
+
14
+ def run(tddium)
15
+ send("run_#{example.example_group.ancestors.map(&:description)[-2][1..-1]}", tddium)
16
+ end
17
+
18
+ def run_suite(tddium)
19
+ tddium.suite
20
+ end
21
+
22
+ def run_spec(tddium)
23
+ tddium.spec
24
+ end
25
+
26
+ def suite_name_prompt(default = default_suite_name)
27
+ "Enter a suite name or press 'Return'. Using '#{default}' by default:"
28
+ end
29
+
30
+ def default_suite_name
31
+ "#{DEFAULT_APP_NAME}/#{DEFAULT_BRANCH_NAME}"
32
+ end
33
+
34
+ def stub_default_suite_name(tddium, default_app_name = DEFAULT_APP_NAME, default_branch_name = DEFAULT_BRANCH_NAME)
35
+ Dir.stub(:pwd).and_return(default_app_name)
36
+ stub_git_branch(tddium, default_branch_name)
37
+ end
38
+
39
+ def stub_ruby_version(tddium, ruby_version = "1.9.2")
40
+ tddium.stub(:`).with("ruby -v").and_return("ruby #{ruby_version} (2010-08-16 patchlevel 302) [i686-darwin10.5.0]")
41
+ end
42
+
43
+ def stub_git_branch(tddium, default_branch_name = DEFAULT_BRANCH_NAME)
44
+ tddium.stub(:`).with("git symbolic-ref HEAD").and_return(default_branch_name)
45
+ end
46
+
47
+ def parse_request_params
48
+ Rack::Utils.parse_nested_query(FakeWeb.last_request.body)
49
+ end
50
+
51
+ def create_file(path, content = "blah")
52
+ FileUtils.mkdir_p(File.dirname(path))
53
+ File.open(path, 'w') do |f|
54
+ f.write(content)
55
+ end
56
+ end
57
+
58
+ def register_uri_options(options = {})
59
+ if options.is_a?(Array)
60
+ options_array = []
61
+ options.each do |sub_options|
62
+ options_array << register_uri_options(sub_options)
63
+ end
64
+ options_array
65
+ else
66
+ options_for_fake_web = {:body => options[:body], :status => options[:status]}
67
+ if options[:response]
68
+ FakeFS.deactivate!
69
+ response = File.open(options[:response]) { |f| f.read }
70
+ FakeFS.activate!
71
+ options_for_fake_web.merge!(:response => response)
72
+ end
73
+ options_for_fake_web
74
+ end
75
+ end
76
+
77
+ def stub_http_response(method, path, options = {})
78
+ FakeWeb.register_uri(method, URI.join(Tddium::API_HOST, "#{Tddium::API_VERSION}/#{path}").to_s, register_uri_options(options))
79
+ end
80
+
81
+ def stub_defaults
82
+ FakeWeb.clean_registry
83
+ tddium.stub(:say)
84
+ stub_git_branch(tddium)
85
+ create_file(".git/something", "something")
86
+ create_file(".tddium", {:branches => {DEFAULT_BRANCH_NAME => DEFAULT_SUITE_ID}, :api_key => DEFAULT_API_KEY}.to_json)
87
+ end
88
+
89
+ def stub_git_push(tddium)
90
+ tddium.stub(:`).with(/^git push/)
91
+ end
92
+
93
+ def stub_sleep(tddium)
94
+ tddium.stub(:sleep).with(Tddium::SLEEP_TIME_BETWEEN_POLLS)
95
+ end
96
+
97
+ let(:tddium) { Tddium.new }
98
+
99
+ shared_examples_for "git repo has not been initialized" do
100
+ context "git repo has not been initialized" do
101
+ before do
102
+ FileUtils.rm_rf(".git")
103
+ end
104
+
105
+ it "should return git is uninitialized" do
106
+ tddium.should_receive(:say).with("git repo must be initialized. Try 'git init'.")
107
+ run(tddium)
108
+ end
109
+ end
110
+ end
111
+
112
+ shared_examples_for ".tddium file is missing or corrupt" do
113
+ context ".tddium file is missing" do
114
+ before do
115
+ FileUtils.rm_rf(".tddium")
116
+ end
117
+
118
+ it "should tell the user '#{Tddium::NOT_INITIALIZED_ERROR}'" do
119
+ tddium.should_receive(:say).with(Tddium::NOT_INITIALIZED_ERROR)
120
+ run(tddium)
121
+ end
122
+ end
123
+
124
+ context ".tddium file is corrupt" do
125
+ before do
126
+ create_file(".tddium", "corrupt file")
127
+ end
128
+
129
+ it "should tell the user '#{Tddium::NOT_INITIALIZED_ERROR}'" do
130
+ tddium.should_receive(:say).with(Tddium::INVALID_TDDIUM_FILE)
131
+ run(tddium)
132
+ end
133
+ end
134
+ end
135
+
136
+ shared_examples_for "sending the api key" do
137
+ it "should include the api key in the headers" do
138
+ run(tddium)
139
+ FakeWeb.last_request[Tddium::API_KEY_HEADER].should == DEFAULT_API_KEY
140
+ end
141
+ end
142
+
143
+ describe "#suite" do
144
+ before do
145
+ stub_defaults
146
+ tddium.stub(:ask).and_return("")
147
+ stub_http_response(:post, Tddium::SUITES_PATH)
148
+ stub_ruby_version(tddium)
149
+ create_file("~/.ssh/id_rsa.pub", "ssh-rsa blah")
150
+ end
151
+
152
+ it "should ask the user for their ssh key" do
153
+ tddium.should_receive(:ask).with(SSH_KEY_PROMPT)
154
+ run_suite(tddium)
155
+ end
156
+
157
+ it "should ask for a suite name" do
158
+ stub_default_suite_name(tddium)
159
+ tddium.should_receive(:ask).with(suite_name_prompt)
160
+ run_suite(tddium)
161
+ end
162
+
163
+ it "should ask for a test file pattern" do
164
+ tddium.should_receive(:ask).with(TEST_PATTERN_PROMPT)
165
+ run_suite(tddium)
166
+ end
167
+
168
+ it "should send a 'POST' request to '#{Tddium::SUITES_PATH}'" do
169
+ run_suite(tddium)
170
+ FakeWeb.last_request.method.should == "POST"
171
+ FakeWeb.last_request.path.should =~ /\/#{Tddium::SUITES_PATH}$/
172
+ end
173
+
174
+ it "should post the current ruby version to the API" do
175
+ stub_ruby_version(tddium, "1.9.2")
176
+ run_suite(tddium)
177
+ parse_request_params["suite"].should include("ruby_version" => "1.9.2")
178
+ end
179
+
180
+ it_should_behave_like "sending the api key"
181
+
182
+ it_should_behave_like "git repo has not been initialized"
183
+ it_should_behave_like ".tddium file is missing or corrupt"
184
+
185
+ context "using defaults" do
186
+ before do
187
+ stub_default_suite_name(tddium)
188
+ end
189
+
190
+ it "should POST the default values to the API" do
191
+ run_suite(tddium)
192
+ parse_request_params["suite"].should include("ssh_key" => "ssh-rsa blah", "suite_name" => default_suite_name,
193
+ "test_pattern" => "**/*_spec.rb")
194
+ end
195
+
196
+ end
197
+
198
+ context "passing arguments" do
199
+ before do
200
+ ssh_key_file = "~/.ssh/blah.txt"
201
+ tddium.stub(:options).and_return(
202
+ :ssh_key => ssh_key_file,
203
+ :name => "my_suite_name",
204
+ :test_pattern => "**/*_test.rb"
205
+ )
206
+ create_file(ssh_key_file, "ssh-rsa 1234")
207
+ end
208
+
209
+ it "should POST the passed in values to the API" do
210
+ run_suite(tddium)
211
+ parse_request_params["suite"].should include("ssh_key" => "ssh-rsa 1234", "suite_name" => "my_suite_name",
212
+ "test_pattern" => "**/*_test.rb")
213
+ end
214
+
215
+ end
216
+
217
+ context "interactive mode" do
218
+ before do
219
+ ssh_key_file = "~/.ssh/foo.txt"
220
+ tddium.stub(:ask).with(SSH_KEY_PROMPT).and_return(ssh_key_file)
221
+ tddium.stub(:ask).with(TEST_PATTERN_PROMPT).and_return("**/*_selenium.rb")
222
+ tddium.stub(:ask).with(suite_name_prompt).and_return("foobar")
223
+ stub_default_suite_name(tddium)
224
+ create_file(ssh_key_file, "ssh-rsa 65431")
225
+ end
226
+
227
+ it "should POST the passed in values to the API" do
228
+ run_suite(tddium)
229
+ parse_request_params["suite"].should include("ssh_key" => "ssh-rsa 65431", "suite_name" => "foobar",
230
+ "test_pattern" => "**/*_selenium.rb")
231
+ end
232
+ end
233
+
234
+ context "API response successful" do
235
+ before do
236
+ stub_http_response(:post, Tddium::SUITES_PATH, :response => fixture_path("post_suites_201.json"))
237
+ tddium.stub(:`).with(/^git remote/)
238
+ stub_git_push(tddium)
239
+ end
240
+
241
+ it "should remove any existing remotes named 'tddium'" do
242
+ tddium.should_receive(:`).with("git remote rm tddium")
243
+ run_suite(tddium)
244
+ end
245
+
246
+ it "should add a new remote called 'tddium'" do
247
+ stub_default_suite_name(tddium)
248
+ tddium.should_receive(:`).with("git remote add tddium ssh://git@api.tddium.com/home/git/repo/#{DEFAULT_APP_NAME}")
249
+ run_suite(tddium)
250
+ end
251
+
252
+ context "in the branch 'oaktree'" do
253
+ before do
254
+ tddium.stub(:current_git_branch).and_return("oaktree")
255
+ end
256
+
257
+ it "should push the current git branch to tddium oaktree" do
258
+ tddium.should_receive(:`).with("git push tddium oaktree")
259
+ run_suite(tddium)
260
+ end
261
+
262
+ it "should create '.tddium' and write the suite_id and branch name" do
263
+ run_suite(tddium)
264
+ tddium_file = File.open(".tddium") { |file| file.read }
265
+ JSON.parse(tddium_file)["branches"]["oaktree"].should == 19 # From response
266
+ end
267
+ end
268
+ end
269
+
270
+ context "API response successful but JSON status not 0" do
271
+ before do
272
+ stub_http_response(:post, Tddium::SUITES_PATH, :response => fixture_path("post_suites_201_json_status_1.json"))
273
+ end
274
+
275
+ it "should do show the explaination" do
276
+ tddium.should_receive(:say).with("An error occured: {:suite_name=>[\"has already been taken\"]}")
277
+ run_suite(tddium)
278
+ end
279
+ end
280
+
281
+ context "API response unsuccessful" do
282
+ before do
283
+ stub_http_response(:post, Tddium::SUITES_PATH, :status => ["501", "Internal Server Error"])
284
+ end
285
+
286
+ it "should show that there was an error" do
287
+ tddium.should_receive(:say).with(/^An error occured: /)
288
+ run_suite(tddium)
289
+ end
290
+
291
+ context "API status code != 0" do
292
+ before do
293
+ stub_http_response(:post, Tddium::SUITES_PATH, :response => fixture_path("post_suites_409.json"))
294
+ end
295
+
296
+ it "should show the error message" do
297
+ tddium.should_receive(:say).with(/Conflict \{\:suite_name\=\>\[\"has already been taken\"\]\}$/)
298
+ run_suite(tddium)
299
+ end
300
+ end
301
+
302
+ context "501 Error" do
303
+ before do
304
+ stub_http_response(:post, Tddium::SUITES_PATH, :status => ["501", "Internal Server Error"])
305
+ end
306
+
307
+ it "should show the HTTP error message" do
308
+ tddium.should_receive(:say).with(/Internal Server Error$/)
309
+ run_suite(tddium)
310
+ end
311
+ end
312
+ end
313
+ end
314
+
315
+ describe "#spec" do
316
+ before do
317
+ stub_defaults
318
+ stub_git_push(tddium)
319
+ stub_http_response(:get, "#{Tddium::SUITES_PATH}/#{DEFAULT_SUITE_ID}")
320
+ end
321
+
322
+ it_should_behave_like "git repo has not been initialized"
323
+ it_should_behave_like ".tddium file is missing or corrupt"
324
+
325
+ it "should push the latest code to tddium" do
326
+ tddium.should_receive(:`).with("git push #{Tddium::GIT_REMOTE_NAME} #{DEFAULT_BRANCH_NAME}")
327
+ run_spec(tddium)
328
+ end
329
+
330
+ it "should send a 'GET' request to '#{Tddium::SUITES_PATH}/#{DEFAULT_SUITE_ID}'" do
331
+ run_spec(tddium)
332
+ FakeWeb.last_request.method.should == "GET"
333
+ FakeWeb.last_request.path.should =~ /#{Tddium::SUITES_PATH}\/#{DEFAULT_SUITE_ID}$/
334
+ end
335
+
336
+ it_should_behave_like "sending the api key"
337
+
338
+ context "'GET #{Tddium::SUITES_PATH}/#{DEFAULT_SUITE_ID}' is successful" do
339
+ before do
340
+ stub_http_response(:get, "#{Tddium::SUITES_PATH}/#{DEFAULT_SUITE_ID}", :response => fixture_path("get_suites_200.json"))
341
+ stub_http_response(:post, Tddium::SESSIONS_PATH)
342
+ create_file("spec/mouse_spec.rb")
343
+ create_file("spec/cat_spec.rb")
344
+ create_file("spec/dog_spec.rb")
345
+ end
346
+
347
+ it "should send a 'POST' request to '#{Tddium::SESSIONS_PATH}'" do
348
+ run_spec(tddium)
349
+ FakeWeb.last_request.method.should == "POST"
350
+ FakeWeb.last_request.path.should =~ /#{Tddium::SESSIONS_PATH}$/
351
+ end
352
+
353
+ it_should_behave_like "sending the api key"
354
+
355
+ context "'POST #{Tddium::SESSIONS_PATH}' is successful" do
356
+ let(:session_id) {7} # from the fixture 'post_sessions_201.json'
357
+ before do
358
+ stub_http_response(:post, "#{Tddium::SESSIONS_PATH}", :response => fixture_path("post_sessions_201.json"))
359
+ stub_http_response(:post, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::REGISTER_TEST_EXECUTIONS_PATH}")
360
+ end
361
+
362
+ it "should send a 'POST' request to '#{Tddium::REGISTER_TEST_EXECUTIONS_PATH}'" do
363
+ run_spec(tddium)
364
+ FakeWeb.last_request.method.should == "POST"
365
+ FakeWeb.last_request.path.should =~ /#{Tddium::REGISTER_TEST_EXECUTIONS_PATH}$/
366
+ end
367
+
368
+ it_should_behave_like "sending the api key"
369
+
370
+ it "should POST the names of the file names extracted from the suite's test_pattern" do
371
+ run_spec(tddium)
372
+ request_params = parse_request_params
373
+ request_params.should include({"suite_id" => DEFAULT_SUITE_ID})
374
+ request_params["tests"][0]["test_name"].should =~ /spec\/cat_spec.rb$/
375
+ request_params["tests"][1]["test_name"].should =~ /spec\/dog_spec.rb$/
376
+ request_params["tests"][2]["test_name"].should =~ /spec\/mouse_spec.rb$/
377
+ request_params["tests"].size.should == 3
378
+ end
379
+
380
+ context "'POST #{Tddium::REGISTER_TEST_EXECUTIONS_PATH}' is successful" do
381
+ before do
382
+ stub_http_response(:post, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::REGISTER_TEST_EXECUTIONS_PATH}", :response => fixture_path("post_register_test_executions_200.json"))
383
+ stub_http_response(:post, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::START_TEST_EXECUTIONS_PATH}")
384
+ end
385
+
386
+ it "should send a 'POST' request to '#{Tddium::START_TEST_EXECUTIONS_PATH}'" do
387
+ run_spec(tddium)
388
+ FakeWeb.last_request.method.should == "POST"
389
+ FakeWeb.last_request.path.should =~ /#{Tddium::START_TEST_EXECUTIONS_PATH}$/
390
+ end
391
+
392
+ it_should_behave_like "sending the api key"
393
+
394
+ context "'POST #{Tddium::START_TEST_EXECUTIONS_PATH}' is successful" do
395
+ before do
396
+ stub_http_response(:post, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::START_TEST_EXECUTIONS_PATH}", :response => fixture_path("post_start_test_executions_200.json"))
397
+ stub_http_response(:get, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::TEST_EXECUTIONS_PATH}")
398
+ end
399
+
400
+ it "should tell the user to '#{Tddium::TERMINATE_PROCESS_INSTRUCTIONS}'" do
401
+ tddium.should_receive(:say).with(Tddium::TERMINATE_PROCESS_INSTRUCTIONS)
402
+ run_spec(tddium)
403
+ end
404
+
405
+ it "should send a 'GET' request to '#{Tddium::TEST_EXECUTIONS_PATH}'" do
406
+ run_spec(tddium)
407
+ FakeWeb.last_request.method.should == "GET"
408
+ FakeWeb.last_request.path.should =~ /#{Tddium::TEST_EXECUTIONS_PATH}$/
409
+ end
410
+
411
+ it_should_behave_like "sending the api key"
412
+
413
+ shared_examples_for("test output summary") do
414
+ it "should display a link to the report" do
415
+ tddium.should_receive(:say).with("You can check out the test report details at http://api.tddium.com/1/sessions/7/test_executions/report")
416
+ run_spec(tddium)
417
+ end
418
+
419
+ it "should display the time taken" do
420
+ tddium.should_receive(:say).with(/^Finished in [\d\.]+ seconds$/)
421
+ run_spec(tddium)
422
+ end
423
+ end
424
+
425
+ context "user presses 'Ctrl-C' during the process" do
426
+ before do
427
+ stub_http_response(:get, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::TEST_EXECUTIONS_PATH}", :response => fixture_path("get_test_executions_200.json"))
428
+ Signal.stub(:trap).with(:INT).and_yield
429
+ stub_sleep(tddium)
430
+ end
431
+
432
+ it "should display '#{Tddium::INTERRUPT_TEXT}'" do
433
+ tddium.should_receive(:say).with(Tddium::INTERRUPT_TEXT)
434
+ run_spec(tddium)
435
+ end
436
+
437
+ it "should display a summary of all the tests" do
438
+ tddium.should_receive(:say).with("3 examples, 1 failures, 0 errors, 1 pending")
439
+ run_spec(tddium)
440
+ end
441
+
442
+ it_should_behave_like("test output summary")
443
+ end
444
+
445
+ context "'GET #{Tddium::TEST_EXECUTIONS_PATH}' is successful" do
446
+ before do
447
+ stub_http_response(:get, "#{Tddium::SESSIONS_PATH}/#{session_id}/#{Tddium::TEST_EXECUTIONS_PATH}", [{:response => fixture_path("get_test_executions_200.json")}, {:response => fixture_path("get_test_executions_200_all_finished.json")}])
448
+ stub_sleep(tddium)
449
+ end
450
+
451
+ it "should sleep for #{Tddium::SLEEP_TIME_BETWEEN_POLLS} seconds" do
452
+ tddium.should_receive(:sleep).exactly(1).times.with(Tddium::SLEEP_TIME_BETWEEN_POLLS)
453
+ run_spec(tddium)
454
+ end
455
+
456
+ it "should display a green '.'" do
457
+ tddium.should_receive(:say).with(".", :green)
458
+ run_spec(tddium)
459
+ end
460
+
461
+ it "should display a red 'F'" do
462
+ tddium.should_receive(:say).with("F", :red)
463
+ run_spec(tddium)
464
+ end
465
+
466
+ it "should display a yellow '*'" do
467
+ tddium.should_receive(:say).with("*", :yellow)
468
+ run_spec(tddium)
469
+ end
470
+
471
+ it "should display 'E' with no color" do
472
+ tddium.should_receive(:say).with("E", nil)
473
+ run_spec(tddium)
474
+ end
475
+
476
+ it "should display a summary of all the tests" do
477
+ tddium.should_receive(:say).with("4 examples, 1 failures, 1 errors, 1 pending")
478
+ run_spec(tddium)
479
+ end
480
+
481
+ it_should_behave_like("test output summary")
482
+
483
+ end
484
+ end
485
+ end
486
+ end
487
+ end
488
+ end
489
+ end
data/tddium.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "tddium/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "tddium-preview"
7
+ s.version = Tddium::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jay Moorthi"]
10
+ s.email = ["info@tddium.com"]
11
+ s.homepage = "http://www.tddium.com/"
12
+ s.summary = %q{tddium Cloud Test Runner}
13
+ s.description = %q{tddium gets your rspec+selenium tests into the cloud by running them on your VMs}
14
+
15
+ s.rubyforge_project = "tddium"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency("thor")
23
+ s.add_runtime_dependency("httparty")
24
+ s.add_runtime_dependency("json")
25
+
26
+ s.add_development_dependency("rspec")
27
+ s.add_development_dependency("fakeweb")
28
+ s.add_development_dependency("rspec")
29
+ s.add_development_dependency("rack-test")
30
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tddium-preview
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jay Moorthi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-08 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: thor
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: httparty
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: json
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rspec
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: fakeweb
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :development
90
+ version_requirements: *id005
91
+ - !ruby/object:Gem::Dependency
92
+ name: rspec
93
+ prerelease: false
94
+ requirement: &id006 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ type: :development
104
+ version_requirements: *id006
105
+ - !ruby/object:Gem::Dependency
106
+ name: rack-test
107
+ prerelease: false
108
+ requirement: &id007 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ type: :development
118
+ version_requirements: *id007
119
+ description: tddium gets your rspec+selenium tests into the cloud by running them on your VMs
120
+ email:
121
+ - info@tddium.com
122
+ executables:
123
+ - tddium
124
+ extensions: []
125
+
126
+ extra_rdoc_files: []
127
+
128
+ files:
129
+ - .document
130
+ - .gitignore
131
+ - CHANGELOG
132
+ - Gemfile
133
+ - LICENSE.txt
134
+ - README.rdoc
135
+ - Rakefile
136
+ - bin/tddium
137
+ - doc/aws-keypair-example.tiff
138
+ - doc/aws-secgroup-example.tiff
139
+ - lib/tddium.rb
140
+ - lib/tddium/version.rb
141
+ - spec/fixtures/get_suites_200.json
142
+ - spec/fixtures/get_test_executions_200.json
143
+ - spec/fixtures/get_test_executions_200_all_finished.json
144
+ - spec/fixtures/post_register_test_executions_200.json
145
+ - spec/fixtures/post_register_test_executions_200_json_status_1.json
146
+ - spec/fixtures/post_sessions_201.json
147
+ - spec/fixtures/post_start_test_executions_200.json
148
+ - spec/fixtures/post_suites_201.json
149
+ - spec/fixtures/post_suites_201_json_status_1.json
150
+ - spec/fixtures/post_suites_409.json
151
+ - spec/spec_helper.rb
152
+ - spec/tddium_spec.rb
153
+ - tddium.gemspec
154
+ has_rdoc: true
155
+ homepage: http://www.tddium.com/
156
+ licenses: []
157
+
158
+ post_install_message:
159
+ rdoc_options: []
160
+
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ none: false
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ hash: 3
169
+ segments:
170
+ - 0
171
+ version: "0"
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ none: false
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ hash: 3
178
+ segments:
179
+ - 0
180
+ version: "0"
181
+ requirements: []
182
+
183
+ rubyforge_project: tddium
184
+ rubygems_version: 1.5.2
185
+ signing_key:
186
+ specification_version: 3
187
+ summary: tddium Cloud Test Runner
188
+ test_files:
189
+ - spec/fixtures/get_suites_200.json
190
+ - spec/fixtures/get_test_executions_200.json
191
+ - spec/fixtures/get_test_executions_200_all_finished.json
192
+ - spec/fixtures/post_register_test_executions_200.json
193
+ - spec/fixtures/post_register_test_executions_200_json_status_1.json
194
+ - spec/fixtures/post_sessions_201.json
195
+ - spec/fixtures/post_start_test_executions_200.json
196
+ - spec/fixtures/post_suites_201.json
197
+ - spec/fixtures/post_suites_201_json_status_1.json
198
+ - spec/fixtures/post_suites_409.json
199
+ - spec/spec_helper.rb
200
+ - spec/tddium_spec.rb