tddium-preview 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/.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