tddium-preview 0.0.1 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/CHANGELOG +4 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +12 -1
- data/README.rdoc +1 -3
- data/Rakefile +31 -0
- data/bin/tddium +2 -4
- data/lib/tddium/constant.rb +124 -0
- data/lib/tddium/version.rb +6 -2
- data/lib/tddium.rb +349 -116
- data/spec/spec_helper.rb +8 -7
- data/spec/tddium_spec.rb +812 -247
- data/tddium.gemspec +10 -5
- metadata +31 -35
- data/doc/aws-keypair-example.tiff +0 -0
- data/doc/aws-secgroup-example.tiff +0 -0
- data/spec/fixtures/get_suites_200.json +0 -13
- data/spec/fixtures/get_test_executions_200.json +0 -13
- data/spec/fixtures/get_test_executions_200_all_finished.json +0 -13
- data/spec/fixtures/post_register_test_executions_200.json +0 -14
- data/spec/fixtures/post_register_test_executions_200_json_status_1.json +0 -14
- data/spec/fixtures/post_sessions_201.json +0 -13
- data/spec/fixtures/post_start_test_executions_200.json +0 -14
- data/spec/fixtures/post_suites_201.json +0 -13
- data/spec/fixtures/post_suites_201_json_status_1.json +0 -13
- data/spec/fixtures/post_suites_409.json +0 -13
data/lib/tddium.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright (c)
|
2
|
+
Copyright (c) 2011 Solano Labs All Rights Reserved
|
3
3
|
=end
|
4
4
|
|
5
5
|
require "rubygems"
|
6
6
|
require "thor"
|
7
|
-
require "
|
7
|
+
require "highline/import"
|
8
8
|
require "json"
|
9
|
+
require "tddium_client"
|
10
|
+
require File.expand_path("../tddium/constant", __FILE__)
|
9
11
|
|
10
12
|
# Usage:
|
11
13
|
#
|
@@ -26,204 +28,435 @@ require "json"
|
|
26
28
|
# tddium help # Print this usage message
|
27
29
|
|
28
30
|
class Tddium < Thor
|
29
|
-
|
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 = {}
|
31
|
+
include TddiumConstant
|
57
32
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
33
|
+
desc "account", "View/Manage account information"
|
34
|
+
method_option :environment, :type => :string, :default => nil
|
35
|
+
method_option :email, :type => :string, :default => nil
|
36
|
+
method_option :password, :type => :string, :default => nil
|
37
|
+
method_option :ssh_key_file, :type => :string, :default => nil
|
38
|
+
def account
|
39
|
+
set_default_environment(options[:environment])
|
40
|
+
if user_logged_in? do |api_response|
|
41
|
+
# User is already logged in, so just display the info
|
42
|
+
show_user_details(api_response)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
params = get_user_credentials(options.merge(:invited => true))
|
62
46
|
|
63
|
-
|
64
|
-
|
65
|
-
|
47
|
+
# Prompt for the password confirmation if password is not from command line
|
48
|
+
unless options[:password]
|
49
|
+
password_confirmation = HighLine.ask(Text::Prompt::PASSWORD_CONFIRMATION) { |q| q.echo = "*" }
|
50
|
+
unless password_confirmation == params[:password]
|
51
|
+
say Text::Process::PASSWORD_CONFIRMATION_INCORRECT
|
52
|
+
return
|
53
|
+
end
|
54
|
+
end
|
66
55
|
|
67
|
-
|
68
|
-
|
69
|
-
|
56
|
+
# Prompt for ssh-key file
|
57
|
+
ssh_file = prompt(Text::Prompt::SSH_KEY, options[:ssh_key_file], Default::SSH_FILE)
|
58
|
+
params[:user_git_pubkey] = File.open(File.expand_path(ssh_file)) {|file| file.read}
|
70
59
|
|
71
|
-
|
60
|
+
# Prompt for accepting license
|
61
|
+
content = File.open(File.join(File.dirname(__FILE__), "..", License::FILE_NAME)) do |file|
|
62
|
+
file.read
|
63
|
+
end
|
64
|
+
say content
|
65
|
+
license_accepted = ask(Text::Prompt::LICENSE_AGREEMENT)
|
66
|
+
return unless license_accepted.downcase == Text::Prompt::Response::AGREE_TO_LICENSE.downcase
|
72
67
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
68
|
+
api_result = call_api(:post, Api::Path::USERS, {:user => params}, false, false) do |api_response|
|
69
|
+
write_api_key(api_response["user"]["api_key"])
|
70
|
+
say Text::Process::ACCOUNT_CREATED % [api_response["user"]["email"], api_response["user"]["recurly_url"]]
|
71
|
+
end
|
72
|
+
say((api_result.api_status == Api::ErrorCode::INVALID_INVITATION) ? Text::Error::INVALID_INVITATION : api_result.message) unless api_result.success?
|
73
|
+
end
|
74
|
+
end
|
78
75
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
76
|
+
desc "login", "Log in to tddium using your email address and password"
|
77
|
+
method_option :environment, :type => :string, :default => nil
|
78
|
+
method_option :email, :type => :string, :default => nil
|
79
|
+
method_option :password, :type => :string, :default => nil
|
80
|
+
def login
|
81
|
+
set_default_environment(options[:environment])
|
82
|
+
if user_logged_in?
|
83
|
+
say Text::Process::ALREADY_LOGGED_IN
|
84
|
+
else
|
85
|
+
login_user(:params => get_user_credentials(options), :show_error => true) do
|
86
|
+
say Text::Process::LOGGED_IN_SUCCESSFULLY
|
84
87
|
end
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|
91
|
+
desc "logout", "Log out of tddium"
|
92
|
+
method_option :environment, :type => :string, :default => nil
|
93
|
+
def logout
|
94
|
+
set_default_environment(options[:environment])
|
95
|
+
FileUtils.rm(tddium_file_name) if File.exists?(tddium_file_name)
|
96
|
+
say Text::Process::LOGGED_OUT_SUCCESSFULLY
|
97
|
+
end
|
98
|
+
|
88
99
|
desc "spec", "Run the test suite"
|
100
|
+
method_option :environment, :type => :string, :default => nil
|
89
101
|
def spec
|
90
|
-
|
102
|
+
set_default_environment(options[:environment])
|
103
|
+
return unless git_repo? && tddium_settings && suite_for_current_branch?
|
91
104
|
|
92
|
-
|
93
|
-
suite_id = tddium_settings["branches"][current_git_branch]
|
105
|
+
start_time = Time.now
|
94
106
|
|
95
107
|
# Push the latest code to git
|
96
|
-
git_push
|
108
|
+
return unless git_push
|
97
109
|
|
98
110
|
# Call the API to get the suite and its tests
|
99
|
-
call_api(:get,
|
111
|
+
call_api(:get, current_suite_path) do |api_response|
|
100
112
|
test_pattern = api_response["suite"]["test_pattern"]
|
101
113
|
test_files = Dir.glob(test_pattern).collect {|file_path| {:test_name => file_path}}
|
102
114
|
|
103
115
|
# Create a session
|
104
|
-
call_api(:post,
|
116
|
+
call_api(:post, Api::Path::SESSIONS) do |api_response|
|
105
117
|
session_id = api_response["session"]["id"]
|
106
118
|
|
107
119
|
# Call the API to register the tests
|
108
|
-
call_api(:post, "#{
|
120
|
+
call_api(:post, "#{Api::Path::SESSIONS}/#{session_id}/#{Api::Path::REGISTER_TEST_EXECUTIONS}", {:suite_id => current_suite_id, :tests => test_files}) do |api_response|
|
109
121
|
# Start the tests
|
110
|
-
call_api(:post, "#{
|
122
|
+
call_api(:post, "#{Api::Path::SESSIONS}/#{session_id}/#{Api::Path::START_TEST_EXECUTIONS}") do |api_response|
|
111
123
|
tests_not_finished_yet = true
|
112
124
|
finished_tests = {}
|
113
125
|
test_statuses = Hash.new(0)
|
114
126
|
api_call_successful = true
|
115
|
-
|
127
|
+
get_test_executions_response = {}
|
128
|
+
|
129
|
+
say Text::Process::STARTING_TEST % test_files.size
|
130
|
+
say Text::Process::TERMINATE_INSTRUCTION
|
116
131
|
while tests_not_finished_yet && api_call_successful do
|
117
132
|
# Poll the API to check the status
|
118
|
-
|
133
|
+
call_api_result = call_api(:get, "#{Api::Path::SESSIONS}/#{session_id}/#{Api::Path::TEST_EXECUTIONS}") do |api_response|
|
134
|
+
# Catch Ctrl-C to interrupt the test
|
119
135
|
Signal.trap(:INT) do
|
120
|
-
say
|
136
|
+
say Text::Process::INTERRUPT
|
137
|
+
say Text::Process::CHECK_TEST_STATUS
|
121
138
|
tests_not_finished_yet = false
|
122
139
|
end
|
140
|
+
|
123
141
|
# Print out the progress of running tests
|
124
142
|
api_response["tests"].each do |test_name, result_params|
|
125
143
|
test_status = result_params["status"]
|
126
144
|
if result_params["end_time"] && !finished_tests[test_name]
|
127
145
|
message = case test_status
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
146
|
+
when "passed" then [".", :green, false]
|
147
|
+
when "failed" then ["F", :red, false]
|
148
|
+
when "error" then ["E", nil, false]
|
149
|
+
when "pending" then ["*", :yellow, false]
|
150
|
+
end
|
133
151
|
finished_tests[test_name] = test_status
|
134
152
|
test_statuses[test_status] += 1
|
135
|
-
say message
|
153
|
+
say *message
|
136
154
|
end
|
137
155
|
end
|
138
156
|
|
157
|
+
# save response for later use
|
158
|
+
get_test_executions_response = api_response
|
159
|
+
|
139
160
|
# If all tests finished, exit the loop else sleep
|
140
|
-
finished_tests.size == api_response["tests"].size
|
161
|
+
if finished_tests.size == api_response["tests"].size
|
162
|
+
tests_not_finished_yet = false
|
163
|
+
else
|
164
|
+
sleep(Default::SLEEP_TIME_BETWEEN_POLLS)
|
165
|
+
end
|
141
166
|
end
|
167
|
+
api_call_successful = call_api_result.success?
|
142
168
|
end
|
143
169
|
|
144
170
|
# Print out the result
|
145
|
-
say
|
171
|
+
say Text::Process::FINISHED_TEST % (Time.now - start_time)
|
146
172
|
say "#{finished_tests.size} examples, #{test_statuses["failed"]} failures, #{test_statuses["error"]} errors, #{test_statuses["pending"]} pending"
|
147
|
-
say
|
173
|
+
say Text::Process::CHECK_TEST_REPORT % get_test_executions_response["report"]
|
148
174
|
end
|
149
175
|
end
|
150
176
|
end
|
151
177
|
end
|
152
178
|
end
|
153
179
|
|
154
|
-
|
180
|
+
desc "status", "Display information about this suite, and any open dev sessions"
|
181
|
+
method_option :environment, :type => :string, :default => nil
|
182
|
+
def status
|
183
|
+
set_default_environment(options[:environment])
|
184
|
+
return unless git_repo? && tddium_settings && suite_for_current_branch?
|
185
|
+
|
186
|
+
call_api(:get, Api::Path::SUITES) do |api_response|
|
187
|
+
if api_response["suites"].size == 0
|
188
|
+
say Text::Status::NO_SUITE
|
189
|
+
else
|
190
|
+
say Text::Status::ALL_SUITES % api_response["suites"].collect {|suite| suite["repo_name"]}.join(", ")
|
191
|
+
|
192
|
+
if current_suite = api_response["suites"].detect {|suite| suite["id"] == current_suite_id}
|
193
|
+
say Text::Status::SEPARATOR
|
194
|
+
say Text::Status::CURRENT_SUITE % current_suite["repo_name"]
|
155
195
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
done = true
|
164
|
-
rescue Timeout::Error
|
165
|
-
ensure
|
166
|
-
tries += 5
|
196
|
+
display_attributes(DisplayedAttributes::SUITE, current_suite)
|
197
|
+
|
198
|
+
show_session_details({:active => true}, Text::Status::NO_ACTIVE_SESSION, Text::Status::ACTIVE_SESSIONS)
|
199
|
+
show_session_details({:active => false, :order => "date", :limit => 10}, Text::Status::NO_INACTIVE_SESSION, Text::Status::INACTIVE_SESSIONS)
|
200
|
+
else
|
201
|
+
say Text::Status::CURRENT_SUITE_UNAVAILABLE
|
202
|
+
end
|
167
203
|
end
|
168
204
|
end
|
205
|
+
end
|
169
206
|
|
170
|
-
|
207
|
+
desc "suite", "Register the suite for this project, or manage its settings"
|
208
|
+
method_option :test_pattern, :type => :string, :default => nil
|
209
|
+
method_option :name, :type => :string, :default => nil
|
210
|
+
method_option :environment, :type => :string, :default => nil
|
211
|
+
def suite
|
212
|
+
set_default_environment(options[:environment])
|
213
|
+
return unless git_repo? && tddium_settings
|
171
214
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
215
|
+
params = {}
|
216
|
+
if current_suite_id
|
217
|
+
call_api(:get, current_suite_path) do |api_response|
|
218
|
+
# Get the current test pattern and prompt for updates
|
219
|
+
params[:test_pattern] = prompt(Text::Prompt::TEST_PATTERN, options[:test_pattern], api_response["suite"]["test_pattern"])
|
220
|
+
|
221
|
+
# Update the current suite if it exists already
|
222
|
+
call_api(:put, current_suite_path, {:suite => params}) do |api_response|
|
223
|
+
say Text::Process::UPDATE_SUITE
|
224
|
+
end
|
177
225
|
end
|
178
226
|
else
|
179
|
-
|
180
|
-
|
227
|
+
params[:branch] = current_git_branch
|
228
|
+
default_suite_name = File.basename(Dir.pwd)
|
229
|
+
params[:repo_name] = options[:name] || default_suite_name
|
230
|
+
|
231
|
+
existing_suite = nil
|
232
|
+
use_existing_suite = false
|
233
|
+
suite_name_resolved = false
|
234
|
+
api_call_successful = true
|
235
|
+
while !suite_name_resolved && api_call_successful
|
236
|
+
# Check to see if there is an existing suite
|
237
|
+
api_call_successful = call_api(:get, Api::Path::SUITES, params) do |api_response|
|
238
|
+
existing_suite = api_response["suites"].first
|
239
|
+
|
240
|
+
# Get the suite name
|
241
|
+
current_suite_name = params[:repo_name]
|
242
|
+
if existing_suite
|
243
|
+
# Prompt for using existing suite (unless suite name is passed from command line) or entering new one
|
244
|
+
params[:repo_name] = prompt(Text::Prompt::USE_EXISTING_SUITE, options[:name], current_suite_name)
|
245
|
+
if options[:name] || params[:repo_name] == Text::Prompt::Response::YES
|
246
|
+
# Use the existing suite, so assign the value back and exit the loop
|
247
|
+
params[:repo_name] = current_suite_name
|
248
|
+
use_existing_suite = true
|
249
|
+
suite_name_resolved = true
|
250
|
+
end
|
251
|
+
elsif current_suite_name == default_suite_name
|
252
|
+
# Prompt for using default suite name or entering new one
|
253
|
+
params[:repo_name] = prompt(Text::Prompt::SUITE_NAME, options[:name], current_suite_name)
|
254
|
+
suite_name_resolved = true if params[:repo_name] == default_suite_name
|
255
|
+
else
|
256
|
+
# Suite name does not exist yet and already prompted
|
257
|
+
suite_name_resolved = true
|
258
|
+
end
|
259
|
+
end.success?
|
260
|
+
end
|
261
|
+
|
262
|
+
if api_call_successful
|
263
|
+
if use_existing_suite
|
264
|
+
# Write to file and exit when using the existing suite
|
265
|
+
write_suite(existing_suite["id"])
|
266
|
+
say Text::Status::USING_SUITE % [existing_suite["repo_name"], existing_suite["branch"]]
|
267
|
+
return
|
268
|
+
end
|
269
|
+
|
270
|
+
params[:ruby_version] = dependency_version(:ruby)
|
271
|
+
params[:bundler_version] = dependency_version(:bundle)
|
272
|
+
params[:rubygems_version] = dependency_version(:gem)
|
273
|
+
|
274
|
+
params[:test_pattern] = prompt(Text::Prompt::TEST_PATTERN, options[:test_pattern], Default::TEST_PATTERN)
|
275
|
+
|
276
|
+
# Create new suite if it does not exist yet
|
277
|
+
call_api(:post, Api::Path::SUITES, {:suite => params}) do |api_response|
|
278
|
+
# Save the created suite
|
279
|
+
write_suite(api_response["suite"]["id"])
|
280
|
+
|
281
|
+
# Manage git
|
282
|
+
`git remote rm #{Git::REMOTE_NAME}`
|
283
|
+
`git remote add #{Git::REMOTE_NAME} #{api_response["suite"]["git_repo_uri"]}`
|
284
|
+
git_push
|
285
|
+
end
|
286
|
+
end
|
181
287
|
end
|
182
|
-
|
183
|
-
|
288
|
+
end
|
289
|
+
|
290
|
+
private
|
291
|
+
|
292
|
+
def call_api(method, api_path, params = {}, api_key = nil, show_error = true, &block)
|
293
|
+
api_key = tddium_settings(:fail_with_message => false)["api_key"] if tddium_settings(:fail_with_message => false) && api_key != false
|
294
|
+
api_status, http_status, error_message = tddium_client.call_api(method, api_path, params, api_key, &block)
|
295
|
+
say error_message if error_message && show_error
|
296
|
+
response = Struct.new(:api_status, :http_status, :message) do
|
297
|
+
def success?
|
298
|
+
self.api_status.to_i.zero?
|
299
|
+
end
|
300
|
+
end
|
301
|
+
response.new(api_status, http_status, error_message)
|
302
|
+
end
|
303
|
+
|
304
|
+
def current_git_branch
|
305
|
+
@current_git_branch ||= File.basename(`git symbolic-ref HEAD`.gsub("\n", ""))
|
306
|
+
end
|
307
|
+
|
308
|
+
def current_suite_id
|
309
|
+
tddium_settings["branches"][current_git_branch] if tddium_settings["branches"]
|
310
|
+
end
|
311
|
+
|
312
|
+
def current_suite_path
|
313
|
+
"#{Api::Path::SUITES}/#{current_suite_id}"
|
314
|
+
end
|
315
|
+
|
316
|
+
def dependency_version(command)
|
317
|
+
`#{command} -v`.match(Dependency::VERSION_REGEXP)[1]
|
318
|
+
end
|
319
|
+
|
320
|
+
def display_attributes(names_to_display, attributes)
|
321
|
+
names_to_display.each do |attr|
|
322
|
+
say Text::Status::ATTRIBUTE_DETAIL % [attr.gsub("_", " ").capitalize, attributes[attr]] if attributes[attr]
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def environment
|
327
|
+
tddium_client.environment
|
328
|
+
end
|
329
|
+
|
330
|
+
def get_user(&block)
|
331
|
+
call_api(:get, Api::Path::USERS, {}, nil, false, &block)
|
332
|
+
end
|
333
|
+
|
334
|
+
def get_user_credentials(options = {})
|
335
|
+
params = {}
|
336
|
+
# prompt for email/invitation and password
|
337
|
+
if options[:invited]
|
338
|
+
params[:invitation_token] = options[:invitation_token] || ask(Text::Prompt::INVITATION_TOKEN)
|
339
|
+
else
|
340
|
+
params[:email] = options[:email] || ask(Text::Prompt::EMAIL)
|
341
|
+
end
|
342
|
+
params[:password] = options[:password] || HighLine.ask(Text::Prompt::PASSWORD) { |q| q.echo = "*" }
|
343
|
+
params
|
184
344
|
end
|
185
345
|
|
186
346
|
def git_push
|
187
|
-
|
347
|
+
system("git push #{Git::REMOTE_NAME} #{current_git_branch}")
|
188
348
|
end
|
189
349
|
|
190
|
-
def
|
191
|
-
|
350
|
+
def git_repo?
|
351
|
+
unless File.exists?(".git")
|
352
|
+
message = Text::Error::GIT_NOT_INITIALIZED
|
353
|
+
say message
|
354
|
+
end
|
355
|
+
message.nil?
|
192
356
|
end
|
193
357
|
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
358
|
+
def login_user(options = {}, &block)
|
359
|
+
# POST (email, password) to /users/sign_in to retrieve an API key
|
360
|
+
login_result = call_api(:post, Api::Path::SIGN_IN, {:user => options[:params]}, false, options[:show_error]) do |api_response|
|
361
|
+
# On success, write the API key to "~/.tddium.<environment>"
|
362
|
+
write_api_key(api_response["api_key"])
|
363
|
+
yield api_response if block_given?
|
364
|
+
end
|
365
|
+
login_result
|
201
366
|
end
|
202
367
|
|
203
|
-
def
|
204
|
-
|
368
|
+
def prompt(text, current_value, default_value)
|
369
|
+
value = current_value || ask(text % default_value)
|
370
|
+
value.empty? ? default_value : value
|
371
|
+
end
|
372
|
+
|
373
|
+
def set_default_environment(env)
|
374
|
+
if env.nil?
|
375
|
+
tddium_client.environment = :development
|
376
|
+
tddium_client.environment = :production unless File.exists?(tddium_file_name)
|
377
|
+
else
|
378
|
+
tddium_client.environment = env.to_sym
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def show_session_details(params, no_session_prompt, all_session_prompt)
|
383
|
+
call_api(:get, Api::Path::SESSIONS, params) do |api_response|
|
384
|
+
say Text::Status::SEPARATOR
|
385
|
+
if api_response["sessions"].size == 0
|
386
|
+
say no_session_prompt
|
387
|
+
else
|
388
|
+
say all_session_prompt
|
389
|
+
api_response["sessions"].each do |session|
|
390
|
+
session_id = session["id"]
|
391
|
+
say Text::Status::SESSION_TITLE % session_id
|
392
|
+
call_api(:get, "#{Api::Path::SESSIONS}/#{session_id}/#{Api::Path::TEST_EXECUTIONS}") do |api_response|
|
393
|
+
display_attributes(DisplayedAttributes::TEST_EXECUTION, api_response)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def show_user_details(api_response)
|
401
|
+
# Given the user is logged in, she should be able to use "tddium account" to display information about her account:
|
402
|
+
# Email address
|
403
|
+
# Account creation date
|
404
|
+
say api_response["user"]["email"]
|
405
|
+
say api_response["user"]["created_at"]
|
406
|
+
say api_response["user"]["recurly_url"]
|
407
|
+
end
|
408
|
+
|
409
|
+
def suite_for_current_branch?
|
410
|
+
unless current_suite_id
|
411
|
+
message = Text::Error::NO_SUITE_EXISTS % current_git_branch
|
412
|
+
say message
|
413
|
+
end
|
414
|
+
message.nil?
|
415
|
+
end
|
416
|
+
|
417
|
+
def tddium_client
|
418
|
+
@tddium_client ||= TddiumClient.new
|
419
|
+
end
|
420
|
+
|
421
|
+
def tddium_file_name
|
422
|
+
extension = ".#{environment}" unless environment == :production
|
423
|
+
".tddium#{extension}"
|
205
424
|
end
|
206
425
|
|
207
|
-
def tddium_settings(
|
208
|
-
unless
|
209
|
-
|
210
|
-
|
426
|
+
def tddium_settings(options = {})
|
427
|
+
options[:fail_with_message] = true unless options[:fail_with_message] == false
|
428
|
+
if @tddium_settings.nil? || options[:force_reload]
|
429
|
+
if File.exists?(tddium_file_name)
|
430
|
+
tddium_config = File.open(tddium_file_name) do |file|
|
211
431
|
file.read
|
212
432
|
end
|
213
433
|
@tddium_settings = JSON.parse(tddium_config) rescue nil
|
214
|
-
say INVALID_TDDIUM_FILE if @tddium_settings.nil? && fail_with_message
|
434
|
+
say (Text::Error::INVALID_TDDIUM_FILE % environment) if @tddium_settings.nil? && options[:fail_with_message]
|
215
435
|
else
|
216
|
-
say
|
436
|
+
say Text::Error::NOT_INITIALIZED if options[:fail_with_message]
|
217
437
|
end
|
218
438
|
end
|
219
439
|
@tddium_settings
|
220
440
|
end
|
221
441
|
|
222
|
-
def
|
223
|
-
|
224
|
-
|
225
|
-
|
442
|
+
def user_logged_in?(active = true, &block)
|
443
|
+
result = tddium_settings(:fail_with_message => false) && tddium_settings["api_key"]
|
444
|
+
(result && active) ? get_user(&block).success? : result
|
445
|
+
end
|
446
|
+
|
447
|
+
def write_api_key(api_key)
|
448
|
+
settings = tddium_settings(:fail_with_message => false) || {}
|
449
|
+
File.open(tddium_file_name, "w") do |file|
|
450
|
+
file.write(settings.merge({"api_key" => api_key}).to_json)
|
226
451
|
end
|
227
|
-
message.nil?
|
228
452
|
end
|
453
|
+
|
454
|
+
def write_suite(suite_id)
|
455
|
+
branches = tddium_settings["branches"] || {}
|
456
|
+
branches.merge!({current_git_branch => suite_id})
|
457
|
+
File.open(tddium_file_name, "w") do |file|
|
458
|
+
file.write(tddium_settings.merge({"branches" => branches}).to_json)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
229
462
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (c) 2011 Solano Labs All Rights Reserved
|
3
|
+
=end
|
4
|
+
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start
|
1
7
|
require "tddium"
|
2
|
-
require
|
3
|
-
require "rack/test"
|
8
|
+
require 'rspec'
|
4
9
|
require "fakefs/spec_helpers"
|
5
|
-
|
6
|
-
|
7
|
-
def fixture_path(fixture_name)
|
8
|
-
File.join File.dirname(__FILE__), "fixtures", fixture_name
|
9
|
-
end
|
10
|
+
require "tddium_client/tddium_spec_helpers"
|