tddium-preview 0.1.5 → 0.5.0

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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tddium-preview (0.1.4)
4
+ tddium-preview (0.1.5)
5
5
  bundler
6
6
  highline
7
7
  json
@@ -14,8 +14,8 @@ GEM
14
14
  crack (0.1.8)
15
15
  diff-lcs (1.1.2)
16
16
  fakefs (0.3.1)
17
- highline (1.6.1)
18
- httparty (0.7.4)
17
+ highline (1.6.2)
18
+ httparty (0.7.7)
19
19
  crack (= 0.1.8)
20
20
  json (1.5.1)
21
21
  rake (0.8.7)
@@ -30,7 +30,7 @@ GEM
30
30
  simplecov (0.4.1)
31
31
  simplecov-html (~> 0.4.3)
32
32
  simplecov-html (0.4.3)
33
- tddium_client (0.0.6)
33
+ tddium_client (0.0.8)
34
34
  httparty
35
35
  json
36
36
  thor (0.14.6)
data/lib/tddium.rb CHANGED
@@ -9,6 +9,7 @@ require "json"
9
9
  require "tddium_client"
10
10
  require "base64"
11
11
  require File.expand_path("../tddium/constant", __FILE__)
12
+ require File.expand_path("../tddium/heroku", __FILE__)
12
13
 
13
14
  # Usage:
14
15
  #
@@ -26,7 +27,7 @@ require File.expand_path("../tddium/constant", __FILE__)
26
27
 
27
28
  class Tddium < Thor
28
29
  include TddiumConstant
29
-
30
+
30
31
  desc "account", "View/Manage account information"
31
32
  method_option :environment, :type => :string, :default => nil
32
33
  method_option :email, :type => :string, :default => nil
@@ -37,6 +38,10 @@ class Tddium < Thor
37
38
  if user_details = user_logged_in?
38
39
  # User is already logged in, so just display the info
39
40
  show_user_details(user_details)
41
+ elsif heroku_config = HerokuConfig.read_config
42
+ # User has logged in to heroku, and TDDIUM environment variables are
43
+ # present
44
+ handle_heroku_user(options, heroku_config)
40
45
  else
41
46
  params = get_user_credentials(options.merge(:invited => true))
42
47
 
@@ -49,9 +54,7 @@ class Tddium < Thor
49
54
  end
50
55
  end
51
56
 
52
- # Prompt for ssh-key file
53
- ssh_file = prompt(Text::Prompt::SSH_KEY, options[:ssh_key_file], Default::SSH_FILE)
54
- params[:user_git_pubkey] = File.open(File.expand_path(ssh_file)) {|file| file.read}
57
+ params[:user_git_pubkey] = prompt_ssh_key(options[:ssh_key_file])
55
58
 
56
59
  # Prompt for accepting license
57
60
  content = File.open(File.join(File.dirname(__FILE__), "..", License::FILE_NAME)) do |file|
@@ -420,6 +423,33 @@ class Tddium < Thor
420
423
  message.nil?
421
424
  end
422
425
 
426
+ def handle_heroku_user(options, heroku_config)
427
+ api_key = heroku_config['TDDIUM_API_KEY']
428
+ user = tddium_client.call_api(:get, Api::Path::USERS, {}, api_key) rescue nil
429
+ if user && user["user"]["heroku_needs_activation"] != true
430
+ say Text::Status::HEROKU_CONFIG
431
+ elsif user
432
+ say Text::Process::HEROKU_WELCOME
433
+ params = get_user_credentials(:email => heroku_config['TDDIUM_USER_NAME'])
434
+ params.delete(:email)
435
+ params[:password_confirmation] = HighLine.ask(Text::Prompt::PASSWORD_CONFIRMATION) { |q| q.echo = "*" }
436
+ params[:user_git_pubkey] = prompt_ssh_key(options[:ssh_key])
437
+
438
+ begin
439
+ user_id = user["user"]["id"]
440
+ result = tddium_client.call_api(:put, "#{Api::Path::USERS}/#{user_id}/", {:user=>params, :heroku_activation=>true}, api_key)
441
+ write_api_key(user["user"]["api_key"])
442
+ say Text::Status::HEROKU_CONFIG
443
+ rescue TddiumClient::Error::API => e
444
+ exit_failure Text::Error::HEROKU_MISCONFIGURED % e
445
+ rescue TddiumClient::Error::Base => e
446
+ exit_failure Text::Error::HEROKU_MISCONFIGURED % e
447
+ end
448
+ else
449
+ exit_failure Text::Error::HEROKU_MISCONFIGURED % "Unrecognized user"
450
+ end
451
+ end
452
+
423
453
  def login_user(options = {})
424
454
  # POST (email, password) to /users/sign_in to retrieve an API key
425
455
  begin
@@ -436,6 +466,14 @@ class Tddium < Thor
436
466
  value.empty? ? default_value : value
437
467
  end
438
468
 
469
+ def prompt_ssh_key(current)
470
+ # Prompt for ssh-key file
471
+ ssh_file = prompt(Text::Prompt::SSH_KEY, options[:ssh_key_file], Default::SSH_FILE)
472
+ data = File.open(File.expand_path(ssh_file)) {|file| file.read}
473
+ data
474
+ end
475
+
476
+
439
477
  def set_default_environment(env)
440
478
  if env.nil?
441
479
  tddium_client.environment = :development
@@ -91,6 +91,13 @@ tddium spec
91
91
  USING_PREVIOUS_USER_DATA_FILE = "Using the previous user data file '%s'"
92
92
  USING_PREVIOUS_MAX_PARALLELISM = "Using the previous value of max_parallelism = %s"
93
93
  USING_PREVIOUS_TEST_PATTERN = "Using the previous value of test_pattern = %s"
94
+ HEROKU_WELCOME = "
95
+ Thanks for installing the Tddium Heroku Add-On!
96
+
97
+ Next, set a password and provide an SSH key to authenticate your communication
98
+ with Tddium.
99
+
100
+ "
94
101
  end
95
102
 
96
103
  module Status
@@ -106,6 +113,20 @@ tddium spec
106
113
  ATTRIBUTE_DETAIL = " %s: %s"
107
114
  SEPARATOR = "====="
108
115
  USING_SUITE = "Using suite: '%s' on branch: '%s'"
116
+ HEROKU_CONFIG = "
117
+ Tddium is configured to work with your Heroku app.
118
+
119
+ Next, you should:
120
+
121
+ 1. Register your test suite by running:
122
+
123
+ $ tddium suite
124
+
125
+ 2. Start tests by running:
126
+
127
+ $ tddium spec
128
+
129
+ "
109
130
  end
110
131
 
111
132
  module Error
@@ -122,6 +143,7 @@ http://blog.tddium.com/home/
122
143
  NO_USER_DATA_FILE = "User data file '%s' does not exist"
123
144
  NO_MATCHING_FILES = "No files match '%s'"
124
145
  PASSWORD_ERROR = "Error changing password: %s"
146
+ HEROKU_MISCONFIGURED = "There was an error linking your Heroku account to Tddium: %s"
125
147
  end
126
148
  end
127
149
 
@@ -0,0 +1,24 @@
1
+ =begin
2
+ Copyright (c) 2011 Solano Labs All Rights Reserved
3
+ =end
4
+
5
+ class HerokuConfig
6
+ def self.read_config
7
+ result = nil
8
+ begin
9
+ config = {}
10
+ output = `heroku config -s`
11
+ output.lines.each do |line|
12
+ line.chomp!
13
+ k, v = line.split('=')
14
+ if k =~ /^TDDIUM_/ && v.length > 0
15
+ config[k] = v
16
+ end
17
+ end
18
+ result = config if config.keys.length > 0
19
+ rescue Errno::ENOENT
20
+ rescue Errno::EPERM
21
+ end
22
+ result
23
+ end
24
+ end
@@ -3,5 +3,5 @@ Copyright (c) 2011 Solano Labs All Rights Reserved
3
3
  =end
4
4
 
5
5
  module TddiumVersion
6
- VERSION = "0.1.5"
6
+ VERSION = "0.5.0"
7
7
  end
@@ -0,0 +1,54 @@
1
+ =begin
2
+ Copyright (c) 2011 Solano Labs All Rights Reserved
3
+ =end
4
+
5
+ require "rubygems"
6
+ require "rspec"
7
+ require "tddium/heroku"
8
+
9
+ describe HerokuConfig do
10
+ SAMPLE_HEROKU_CONFIG_TDDIUM = "
11
+ TDDIUM_API_KEY=abcdefg
12
+ TDDIUM_USER_NAME=app1234@heroku.com
13
+ "
14
+ SAMPLE_HEROKU_CONFIG_NO_TDDIUM = "
15
+ DB_URL=postgres://foo/bar
16
+ "
17
+ describe ".read_config" do
18
+ context "addon installed" do
19
+ before do
20
+ HerokuConfig.stub(:`).with("heroku config -s").and_return(SAMPLE_HEROKU_CONFIG_TDDIUM)
21
+ end
22
+
23
+ it "should return a hash of the TDDIUM config vars" do
24
+ result = HerokuConfig.read_config
25
+ result.should be_a(Hash)
26
+ result.each do |k,v|
27
+ k.should =~ /^TDDIUM_/
28
+ v.length.should > 0
29
+ end
30
+ result.should include('TDDIUM_API_KEY')
31
+ result['TDDIUM_API_KEY'].should == 'abcdefg'
32
+ end
33
+ end
34
+
35
+ context "addon not installed" do
36
+ before do
37
+ HerokuConfig.stub(:`).with("heroku config -s").and_return(SAMPLE_HEROKU_CONFIG_NO_TDDIUM)
38
+ end
39
+
40
+ it "should return nil" do
41
+ HerokuConfig.read_config.should be_nil
42
+ end
43
+ end
44
+
45
+ context "heroku not installed" do
46
+ before do
47
+ HerokuConfig.stub(:`).with("heroku config -s").and_raise(Errno::ENOENT)
48
+ end
49
+ it "should return nil" do
50
+ HerokuConfig.read_config.should be_nil
51
+ end
52
+ end
53
+ end
54
+ end
data/spec/tddium_spec.rb CHANGED
@@ -21,6 +21,7 @@ describe Tddium do
21
21
  SAMPLE_FILE_PATH2 = "./my_user_file2.png"
22
22
  SAMPLE_INVITATION_TOKEN = "TZce3NueiXp2lMTmaeRr"
23
23
  SAMPLE_GIT_REPO_URI = "ssh://git@api.tddium.com/home/git/repo/#{SAMPLE_APP_NAME}"
24
+ SAMPLE_HEROKU_CONFIG = {"TDDIUM_API_KEY" => SAMPLE_API_KEY, "TDDIUM_USER_NAME" => SAMPLE_EMAIL}
24
25
  SAMPLE_LICENSE_TEXT = "LICENSE"
25
26
  SAMPLE_PASSWORD = "foobar"
26
27
  SAMPLE_NEW_PASSWORD = "foobar2"
@@ -37,7 +38,20 @@ describe Tddium do
37
38
  SAMPLE_SUITES_RESPONSE = {"suites" => [SAMPLE_SUITE_RESPONSE]}
38
39
  SAMPLE_TDDIUM_CONFIG_FILE = ".tddium.test"
39
40
  SAMPLE_TEST_EXECUTION_STATS = "total 1, notstarted 0, started 1, passed 0, failed 0, pending 0, error 0", "start_time"
40
- SAMPLE_USER_RESPONSE = {"user"=> {"id"=>SAMPLE_USER_ID, "api_key" => SAMPLE_API_KEY, "email" => SAMPLE_EMAIL, "created_at" => SAMPLE_DATE_TIME, "recurly_url" => SAMPLE_RECURLY_URL}}
41
+ SAMPLE_USER_RESPONSE = {"status"=>0, "user"=>
42
+ { "id"=>SAMPLE_USER_ID,
43
+ "api_key" => SAMPLE_API_KEY,
44
+ "email" => SAMPLE_EMAIL,
45
+ "created_at" => SAMPLE_DATE_TIME,
46
+ "recurly_url" => SAMPLE_RECURLY_URL}}
47
+ SAMPLE_SSH_PUBKEY = "ssh-rsa 1234567890"
48
+ SAMPLE_HEROKU_USER_RESPONSE = {"user"=>
49
+ { "id"=>SAMPLE_USER_ID,
50
+ "api_key" => SAMPLE_API_KEY,
51
+ "email" => SAMPLE_EMAIL,
52
+ "created_at" => SAMPLE_DATE_TIME,
53
+ "heroku_needs_activation" => true,
54
+ "recurly_url" => SAMPLE_RECURLY_URL}}
41
55
  PASSWORD_ERROR_EXPLANATION = "bad confirmation"
42
56
  PASSWORD_ERROR_RESPONSE = {"status"=>1, "explanation"=> PASSWORD_ERROR_EXPLANATION}
43
57
 
@@ -91,7 +105,10 @@ describe Tddium do
91
105
  tddium_client_result = mock(TddiumClient::Result::API)
92
106
  response_mocks << tddium_client_result
93
107
  else
94
- tddium_client_result = mock(TddiumClient::Error::API, :body => current_response.to_json)
108
+ tddium_client_result = mock(TddiumClient::Error::API)
109
+ tddium_client_result.stub(:body => current_response.to_json,
110
+ :code => 200,
111
+ :response => mock(:header => mock(:msg => "OK")))
95
112
  result.and_raise(TddiumClient::Error::API.new(tddium_client_result))
96
113
  end
97
114
  current_response.each do |k, v|
@@ -157,7 +174,9 @@ describe Tddium do
157
174
  def stub_tddium_client
158
175
  TddiumClient::Client.stub(:new).and_return(tddium_client)
159
176
  tddium_client.stub(:environment).and_return("test")
160
- tddium_client.stub(:call_api).and_raise(TddiumClient::Error::Base)
177
+ tddium_client.stub(:call_api) do |x,y,z,k|
178
+ raise TddiumClient::Error::Base.new("unstubbed call_api(#{x.inspect},#{y.inspect},#{z.inspect},#{k.inspect})")
179
+ end
161
180
  end
162
181
 
163
182
  let(:tddium) { Tddium.new }
@@ -440,7 +459,7 @@ describe Tddium do
440
459
  tddium.stub(:ask).and_return("")
441
460
  HighLine.stub(:ask).and_return("")
442
461
  create_file(File.join(File.dirname(__FILE__), "..", Tddium::License::FILE_NAME), SAMPLE_LICENSE_TEXT)
443
- create_file(Tddium::Default::SSH_FILE, "ssh-rsa blah")
462
+ create_file(Tddium::Default::SSH_FILE, SAMPLE_SSH_PUBKEY)
444
463
  end
445
464
 
446
465
  it_should_behave_like "set the default environment"
@@ -468,6 +487,122 @@ describe Tddium do
468
487
 
469
488
  end
470
489
 
490
+ shared_examples_for "prompt for ssh key" do
491
+ context "--ssh-key-file is not supplied" do
492
+ it "should prompt the user for their ssh key file" do
493
+ tddium.should_receive(:ask).with(Tddium::Text::Prompt::SSH_KEY % Tddium::Default::SSH_FILE)
494
+ run_account(tddium)
495
+ end
496
+ end
497
+
498
+ context "--ssh-key-file is supplied" do
499
+ it "should not prompt the user for their ssh key file" do
500
+ tddium.should_not_receive(:ask).with(Tddium::Text::Prompt::SSH_KEY % Tddium::Default::SSH_FILE)
501
+ run_account(tddium, :ssh_key_file => Tddium::Default::SSH_FILE)
502
+ end
503
+ end
504
+ end
505
+
506
+ def account_should_fail(options={})
507
+ options[:environment] = "test" unless options.has_key?(:environment)
508
+ stub_cli_options(tddium, options)
509
+ tddium.stub(:exit_failure).and_raise(SystemExit)
510
+ yield if block_given?
511
+ expect { tddium.account }.to raise_error(SystemExit)
512
+ end
513
+
514
+ context "the user is logged in to heroku, but not to tddium" do
515
+ before do
516
+ HerokuConfig.stub(:read_config).and_return(SAMPLE_HEROKU_CONFIG)
517
+ @user_path = "#{Tddium::Api::Path::USERS}/#{SAMPLE_USER_ID}/"
518
+ end
519
+
520
+ context "the user has a properly configured add-on" do
521
+
522
+ context "first-time account activation" do
523
+ before do
524
+ stub_call_api_response(:get, Tddium::Api::Path::USERS, SAMPLE_HEROKU_USER_RESPONSE)
525
+ stub_call_api_response(:put, @user_path, {"status"=>0})
526
+ end
527
+
528
+ it_behaves_like "prompting for password" do
529
+ let(:password_prompt) {Tddium::Text::Prompt::PASSWORD}
530
+ end
531
+
532
+ it_behaves_like "prompting for password" do
533
+ let(:password_prompt) {Tddium::Text::Prompt::PASSWORD_CONFIRMATION}
534
+ end
535
+
536
+ it_behaves_like "prompt for ssh key"
537
+
538
+ it "should display the heroku welcome" do
539
+ tddium.should_receive(:say).with(Tddium::Text::Process::HEROKU_WELCOME)
540
+ run_account(tddium)
541
+ end
542
+
543
+ it "should send a 'PUT' request to user_path with passwords" do
544
+ HighLine.stub(:ask).with(Tddium::Text::Prompt::PASSWORD).and_return(SAMPLE_PASSWORD)
545
+ HighLine.stub(:ask).with(Tddium::Text::Prompt::PASSWORD_CONFIRMATION).and_return(SAMPLE_PASSWORD)
546
+ call_api_should_receive(:method => :put,
547
+ :path => /#{@user_path}$/,
548
+ :params => {:user =>
549
+ {:password => SAMPLE_PASSWORD,
550
+ :password_confirmation => SAMPLE_PASSWORD,
551
+ :user_git_pubkey => SAMPLE_SSH_PUBKEY},
552
+ :heroku_activation => true},
553
+ :api_key => SAMPLE_API_KEY)
554
+ account_should_fail # call_api_should_receive stubs call_api with an error
555
+ end
556
+
557
+ context "PUT with passwords is successful" do
558
+ before do
559
+ stub_call_api_response(:put, @user_path, {"status"=>0})
560
+ end
561
+
562
+ it_should_behave_like "writing the api key to the .tddium file"
563
+
564
+ it "should display the heroku configured welcome" do
565
+ tddium.should_receive(:say).with(Tddium::Text::Status::HEROKU_CONFIG)
566
+ run_account(tddium)
567
+ end
568
+ end
569
+
570
+ context "PUT is unsuccessful" do
571
+ before do
572
+ stub_call_api_response(:put, @user_path, {"status" => 1, "explanation"=> "PUT error"})
573
+ end
574
+
575
+ it "should display an error message and fail" do
576
+ account_should_fail do
577
+ tddium.should_receive(:exit_failure).with(Tddium::Text::Error::HEROKU_MISCONFIGURED % "200 OK (1) PUT error")
578
+ end
579
+ end
580
+ end
581
+ end
582
+
583
+ context "re-run after account is activated" do
584
+ before do
585
+ stub_call_api_response(:get, Tddium::Api::Path::USERS, SAMPLE_USER_RESPONSE)
586
+ end
587
+
588
+ it "should display the heroku configured welcome" do
589
+ tddium.should_receive(:say).with(Tddium::Text::Status::HEROKU_CONFIG)
590
+ run_account(tddium)
591
+ end
592
+ end
593
+ end
594
+
595
+ context "the heroku config contains an unrecognized API key" do
596
+ let(:call_api_result) {[403, "Forbidden"]}
597
+
598
+ it "should display an error message and fail" do
599
+ account_should_fail do
600
+ tddium.should_receive(:exit_failure).with(Tddium::Text::Error::HEROKU_MISCONFIGURED % "Unrecognized user")
601
+ end
602
+ end
603
+ end
604
+ end
605
+
471
606
  context "the user is not already logged in" do
472
607
  let(:call_api_result) {[403, "Forbidden"]}
473
608
 
@@ -489,19 +624,7 @@ describe Tddium do
489
624
  HighLine.stub(:ask).with(Tddium::Text::Prompt::PASSWORD_CONFIRMATION).and_return(SAMPLE_PASSWORD)
490
625
  end
491
626
 
492
- context "--ssh-key-file is not supplied" do
493
- it "should prompt the user for their ssh key file" do
494
- tddium.should_receive(:ask).with(Tddium::Text::Prompt::SSH_KEY % Tddium::Default::SSH_FILE)
495
- run_account(tddium)
496
- end
497
- end
498
-
499
- context "--ssh-key-file is supplied" do
500
- it "should not prompt the user for their ssh key file" do
501
- tddium.should_not_receive(:ask).with(Tddium::Text::Prompt::SSH_KEY % Tddium::Default::SSH_FILE)
502
- run_account(tddium, :ssh_key_file => Tddium::Default::SSH_FILE)
503
- end
504
- end
627
+ it_behaves_like "prompt for ssh key"
505
628
 
506
629
  it "should show the user the license" do
507
630
  tddium.should_receive(:say).with(SAMPLE_LICENSE_TEXT)
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: tddium-preview
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.5
5
+ version: 0.5.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Solano Labs
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-08 00:00:00 -07:00
13
+ date: 2011-05-27 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -138,7 +138,9 @@ files:
138
138
  - bin/tddium
139
139
  - lib/tddium.rb
140
140
  - lib/tddium/constant.rb
141
+ - lib/tddium/heroku.rb
141
142
  - lib/tddium/version.rb
143
+ - spec/heroku_spec.rb
142
144
  - spec/spec_helper.rb
143
145
  - spec/tddium_spec.rb
144
146
  - tddium.gemspec
@@ -166,10 +168,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
168
  requirements: []
167
169
 
168
170
  rubyforge_project: tddium
169
- rubygems_version: 1.5.2
171
+ rubygems_version: 1.6.2
170
172
  signing_key:
171
173
  specification_version: 3
172
174
  summary: tddium Hosted Ruby Testing
173
- test_files:
174
- - spec/spec_helper.rb
175
- - spec/tddium_spec.rb
175
+ test_files: []
176
+