shelly 0.0.43 → 0.0.44.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,21 +24,23 @@ describe Shelly::CLI::Main do
24
24
  it "should display available commands" do
25
25
  expected = <<-OUT
26
26
  Tasks:
27
- shelly add # Adds new cloud to Shelly Cloud
28
- shelly backup <command> # Manages database backups from this cloud
29
- shelly config <command> # Manages cloud configuration files
30
- shelly delete # Delete cloud from Shelly Cloud
31
- shelly deploys <command> # View cloud deploy logs
27
+ shelly add # Add a new cloud
28
+ shelly backup <command> # Manage database backups
29
+ shelly config <command> # Manage application configuration files
30
+ shelly delete # Delete the cloud
31
+ shelly deploys <command> # View deploy logs
32
32
  shelly help [TASK] # Describe available tasks or one specific task
33
- shelly ip # Lists clouds IP's
34
- shelly list # Lists all your clouds
35
- shelly login [EMAIL] # Logs user in to Shelly Cloud
36
- shelly logs # Show latest application logs from each instance
37
- shelly register [EMAIL] # Registers new user account on Shelly Cloud
38
- shelly start # Starts the cloud
39
- shelly stop # Stops the cloud
40
- shelly user <command> # Manages users using this cloud
41
- shelly version # Displays shelly version
33
+ shelly ip # List cloud's IP addresses
34
+ shelly list # List available clouds
35
+ shelly login [EMAIL] # Log into Shelly Cloud
36
+ shelly logout # Logout from Shelly Cloud
37
+ shelly logs # Show latest application logs
38
+ shelly redeploy # Redeploy application
39
+ shelly register [EMAIL] # Register new account
40
+ shelly start # Start the cloud
41
+ shelly stop # Stop the cloud
42
+ shelly user <command> # Manage collaborators
43
+ shelly version # Display shelly version
42
44
 
43
45
  Options:
44
46
  [--debug] # Show debug information
@@ -53,10 +55,10 @@ Usage:
53
55
  shelly logs
54
56
 
55
57
  Options:
56
- -c, [--cloud=CLOUD] # Specify which cloud to show logs for
58
+ -c, [--cloud=CLOUD] # Specify cloud
57
59
  [--debug] # Show debug information
58
60
 
59
- Show latest application logs from each instance
61
+ Show latest application logs
60
62
  OUT
61
63
  out = IO.popen("bin/shelly help logs").read.strip
62
64
  out.should == expected.strip
@@ -85,7 +87,7 @@ OUT
85
87
  end
86
88
 
87
89
  it "should check ssh key in database" do
88
- @user.stub(:ssh_key_registered?).and_raise(RestClient::Conflict)
90
+ @user.stub(:ssh_key_registered?).and_raise(Shelly::Client::ConflictException.new)
89
91
  $stdout.should_receive(:puts).with("\e[31mUser with your ssh key already exists.\e[0m")
90
92
  $stdout.should_receive(:puts).with("\e[31mYou can login using: shelly login [EMAIL]\e[0m")
91
93
  lambda {
@@ -172,8 +174,8 @@ OUT
172
174
 
173
175
  context "on unsuccessful registration" do
174
176
  it "should display errors and exit with 1" do
175
- response = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
176
- exception = Shelly::Client::APIError.new(422, response)
177
+ body = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
178
+ exception = Shelly::Client::ValidationException.new(body)
177
179
  @client.stub(:register_user).and_raise(exception)
178
180
  $stdout.should_receive(:puts).with("\e[31mEmail has been already taken\e[0m")
179
181
  lambda {
@@ -252,7 +254,7 @@ OUT
252
254
  context "on unauthorized user" do
253
255
  it "should exit with 1 and display error message" do
254
256
  response = {"message" => "Unauthorized", "url" => "https://admin.winniecloud.com/users/password/new"}
255
- exception = Shelly::Client::APIError.new(401, response)
257
+ exception = Shelly::Client::UnauthorizedException.new(response)
256
258
  @client.stub(:token).and_raise(exception)
257
259
  $stdout.should_receive(:puts).with("\e[31mWrong email or password\e[0m")
258
260
  $stdout.should_receive(:puts).with("\e[31mYou can reset password by using link:\e[0m")
@@ -281,6 +283,7 @@ OUT
281
283
  @client.stub(:token).and_return("abc")
282
284
  end
283
285
 
286
+ # This spec tests inside_git_repository? hook
284
287
  it "should exit with message if command run outside git repository" do
285
288
  Shelly::App.stub(:inside_git_repository?).and_return(false)
286
289
  $stdout.should_receive(:puts).with("\e[31mMust be run inside your project git repository\e[0m")
@@ -291,8 +294,19 @@ OUT
291
294
  }.should raise_error(SystemExit)
292
295
  end
293
296
 
294
- context "command line options" do
297
+ # This spec tests logged_in? hook
298
+ it "should exit with message if user is not logged in" do
299
+ exception = Shelly::Client::UnauthorizedException.new
300
+ @client.stub(:token).and_raise(exception)
301
+ $stdout.should_receive(:puts).with(red "You are not logged in. To log in use: `shelly login`")
302
+ lambda {
303
+ fake_stdin(["", ""]) do
304
+ invoke(@main, :add)
305
+ end
306
+ }.should raise_error(SystemExit)
307
+ end
295
308
 
309
+ context "command line options" do
296
310
  context "invalid params" do
297
311
  it "should show help and exit if not all options are passed" do
298
312
  $stdout.should_receive(:puts).with("\e[31mTry 'shelly help add' for more information\e[0m")
@@ -363,6 +377,15 @@ OUT
363
377
  end
364
378
  end
365
379
 
380
+ context "when user provided 'none' database" do
381
+ it "shouldn't take it into account" do
382
+ @app.should_receive(:databases=).with(["postgresql"])
383
+ fake_stdin(["", "postgresql, none"]) do
384
+ invoke(@main, :add)
385
+ end
386
+ end
387
+ end
388
+
366
389
  it "should create the app on shelly cloud" do
367
390
  @app.should_receive(:create)
368
391
  fake_stdin(["", ""]) do
@@ -371,8 +394,8 @@ OUT
371
394
  end
372
395
 
373
396
  it "should display validation errors if they are any" do
374
- response = {"message" => "Validation Failed", "errors" => [["code_name", "has been already taken"]]}
375
- exception = Shelly::Client::APIError.new(422, response)
397
+ body = {"message" => "Validation Failed", "errors" => [["code_name", "has been already taken"]]}
398
+ exception = Shelly::Client::ValidationException.new(body)
376
399
  @app.should_receive(:create).and_raise(exception)
377
400
  $stdout.should_receive(:puts).with("\e[31mCode name has been already taken\e[0m")
378
401
  $stdout.should_receive(:puts).with("\e[31mFix erros in the below command and type it again to create your cloud\e[0m")
@@ -439,6 +462,10 @@ OUT
439
462
  Shelly::User.stub(:new).and_return(@user)
440
463
  end
441
464
 
465
+ it "should ensure user has logged in" do
466
+ hooks(@main, :list).should include(:logged_in?)
467
+ end
468
+
442
469
  it "should display user's clouds" do
443
470
  $stdout.should_receive(:puts).with("\e[32mYou have following clouds available:\e[0m")
444
471
  $stdout.should_receive(:puts).with(/abc\s+\| running/)
@@ -457,18 +484,6 @@ OUT
457
484
  $stdout.should_receive(:puts).with("\e[32mYou have no clouds yet\e[0m")
458
485
  invoke(@main, :status)
459
486
  end
460
-
461
- context "on failure" do
462
- it "should display info that user is not logged in" do
463
- error = Shelly::Client::APIError.new(401)
464
- @client.stub(:token).and_raise(error)
465
- $stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
466
- $stdout.should_receive(:puts).with(" shelly login")
467
- lambda {
468
- invoke(@main, :list)
469
- }.should raise_error(SystemExit)
470
- end
471
- end
472
487
  end
473
488
 
474
489
  describe "#start" do
@@ -484,6 +499,7 @@ OUT
484
499
  Shelly::App.stub(:new).and_return(@app)
485
500
  end
486
501
 
502
+ # This spec tests cloudfile_present? hook
487
503
  it "should exit if there is no Cloudfile" do
488
504
  File.delete("Cloudfile")
489
505
  $stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
@@ -492,22 +508,17 @@ OUT
492
508
  }.should raise_error(SystemExit)
493
509
  end
494
510
 
511
+ it "should ensure user has logged in" do
512
+ hooks(@main, :start).should include(:logged_in?)
513
+ end
514
+
495
515
  it "should exit if user doesn't have access to clouds in Cloudfile" do
496
- response = {"message" => "Couldn't find Cloud with"}
497
- exception = Shelly::Client::APIError.new(404, response)
516
+ exception = Shelly::Client::NotFoundException.new("resource" => "cloud")
498
517
  @client.stub(:start_cloud).and_raise(exception)
499
518
  $stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
500
519
  lambda { invoke(@main, :start) }.should raise_error(SystemExit)
501
520
  end
502
521
 
503
- it "should exit if user is not logged in" do
504
- exception = Shelly::Client::APIError.new(401)
505
- @client.stub(:token).and_raise(exception)
506
- $stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
507
- $stdout.should_receive(:puts).with(" shelly login")
508
- lambda { invoke(@main, :start) }.should raise_error(SystemExit)
509
- end
510
-
511
522
  context "single cloud in Cloudfile" do
512
523
  it "should start the cloud" do
513
524
  @client.stub(:start_cloud)
@@ -523,8 +534,8 @@ OUT
523
534
  end
524
535
 
525
536
  it "should show information to start specific cloud and exit" do
526
- $stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to start using:")
527
- $stdout.should_receive(:puts).with(" shelly start --cloud foo-production")
537
+ $stdout.should_receive(:puts).with(red "You have multiple clouds in Cloudfile.")
538
+ $stdout.should_receive(:puts).with("Select cloud using `shelly start --cloud foo-production`")
528
539
  $stdout.should_receive(:puts).with("Available clouds:")
529
540
  $stdout.should_receive(:puts).with(" * foo-production")
530
541
  $stdout.should_receive(:puts).with(" * foo-staging")
@@ -542,21 +553,21 @@ OUT
542
553
 
543
554
  context "on failure" do
544
555
  it "should show information that cloud is running" do
545
- raise_conflict(:state => "running")
556
+ raise_conflict("state" => "running")
546
557
  $stdout.should_receive(:puts).with(red "Not starting: cloud 'foo-production' is already running")
547
558
  lambda { invoke(@main, :start) }.should raise_error(SystemExit)
548
559
  end
549
560
 
550
561
  %w{deploying configuring}.each do |state|
551
562
  it "should show information that cloud is #{state}" do
552
- raise_conflict(:state => state)
563
+ raise_conflict("state" => state)
553
564
  $stdout.should_receive(:puts).with(red "Not starting: cloud 'foo-production' is currently deploying")
554
565
  lambda { invoke(@main, :start) }.should raise_error(SystemExit)
555
566
  end
556
567
  end
557
568
 
558
569
  it "should show information that cloud has no code" do
559
- raise_conflict(:state => "no_code")
570
+ raise_conflict("state" => "no_code")
560
571
  $stdout.should_receive(:puts).with(red "Not starting: no source code provided")
561
572
  $stdout.should_receive(:puts).with(red "Push source code using:")
562
573
  $stdout.should_receive(:puts).with(" git push production master")
@@ -565,24 +576,25 @@ OUT
565
576
 
566
577
  %w{deploy_failed configuration_failed}.each do |state|
567
578
  it "should show information that cloud #{state}" do
568
- raise_conflict(:state => state, :link => "http://example.com/logs")
579
+ raise_conflict("state" => state)
569
580
  $stdout.should_receive(:puts).with(red "Not starting: deployment failed")
570
581
  $stdout.should_receive(:puts).with(red "Support has been notified")
571
- $stdout.should_receive(:puts).with(red "See http://example.com/logs for reasons of failure")
582
+ $stdout.should_receive(:puts).
583
+ with(red "Check `shelly deploys show last --cloud foo-production` for reasons of failure")
572
584
  lambda { invoke(@main, :start) }.should raise_error(SystemExit)
573
585
  end
574
586
  end
587
+
575
588
  it "should open billing page" do
576
- raise_conflict(:state => "no_billing")
589
+ raise_conflict("state" => "no_billing")
577
590
  $stdout.should_receive(:puts).with(red "Please fill in billing details to start foo-production. Opening browser.")
578
591
  @app.should_receive(:open_billing_page)
579
592
  lambda { invoke(@main, :start) }.should raise_error(SystemExit)
580
593
  end
581
594
 
582
595
  def raise_conflict(options = {})
583
- options = {:state => "no_code"}.merge(options)
584
- exception = RestClient::Conflict.new
585
- exception.stub(:response).and_return(options.to_json)
596
+ body = {"state" => "no_code"}.merge(options)
597
+ exception = Shelly::Client::ConflictException.new(body)
586
598
  @client.stub(:start_cloud).and_raise(exception)
587
599
  end
588
600
  end
@@ -601,24 +613,17 @@ OUT
601
613
  Shelly::App.stub(:new).and_return(@app)
602
614
  end
603
615
 
604
- it "should exit if there is no Cloudfile" do
605
- File.delete("Cloudfile")
606
- $stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
607
- lambda {
608
- invoke(@main, :stop)
609
- }.should raise_error(SystemExit)
616
+ it "should ensure user has logged in" do
617
+ hooks(@main, :stop).should include(:logged_in?)
610
618
  end
611
619
 
612
- it "should exit if user doesn't have access to clouds in Cloudfile" do
613
- @client.stub(:stop_cloud).and_raise(Shelly::Client::APIError.new(404))
614
- $stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
615
- lambda { invoke(@main, :stop) }.should raise_error(SystemExit)
620
+ it "should ensure that Cloudfile is present" do
621
+ hooks(@main, :stop).should include(:cloudfile_present?)
616
622
  end
617
623
 
618
- it "should exit if user is not logged in" do
619
- @client.stub(:token).and_raise(Shelly::Client::APIError.new(401))
620
- $stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
621
- $stdout.should_receive(:puts).with(" shelly login")
624
+ it "should exit if user doesn't have access to clouds in Cloudfile" do
625
+ @client.stub(:stop_cloud).and_raise(Shelly::Client::NotFoundException.new("resource" => "cloud"))
626
+ $stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
622
627
  lambda { invoke(@main, :stop) }.should raise_error(SystemExit)
623
628
  end
624
629
 
@@ -636,8 +641,8 @@ OUT
636
641
  end
637
642
 
638
643
  it "should show information to start specific cloud and exit" do
639
- $stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to stop using:")
640
- $stdout.should_receive(:puts).with(" shelly stop --cloud foo-production")
644
+ $stdout.should_receive(:puts).with(red "You have multiple clouds in Cloudfile.")
645
+ $stdout.should_receive(:puts).with("Select cloud using `shelly stop --cloud foo-production`")
641
646
  $stdout.should_receive(:puts).with("Available clouds:")
642
647
  $stdout.should_receive(:puts).with(" * foo-production")
643
648
  $stdout.should_receive(:puts).with(" * foo-staging")
@@ -653,18 +658,18 @@ OUT
653
658
  end
654
659
  end
655
660
 
656
- describe "#ips" do
661
+ describe "#ip" do
657
662
  before do
658
663
  File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
659
- Shelly::App.stub(:inside_git_repository?).and_return(true)
664
+ @main.stub(:logged_in?).and_return(true)
660
665
  end
661
666
 
662
- it "should exit with message if there is no Cloudfile" do
663
- File.delete("Cloudfile")
664
- $stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
665
- lambda {
666
- invoke(@main, :ip)
667
- }.should raise_error(SystemExit)
667
+ it "should ensure user has logged in" do
668
+ hooks(@main, :ip).should include(:logged_in?)
669
+ end
670
+
671
+ it "should ensure that Cloudfile is present" do
672
+ hooks(@main, :ip).should include(:cloudfile_present?)
668
673
  end
669
674
 
670
675
  context "on success" do
@@ -683,7 +688,7 @@ OUT
683
688
 
684
689
  context "on failure" do
685
690
  it "should raise an error if user does not have access to cloud" do
686
- exception = Shelly::Client::APIError.new(404, {"message" => "Cloud foo-staging not found"})
691
+ exception = Shelly::Client::NotFoundException.new("resource" => "cloud")
687
692
  @client.stub(:app).and_raise(exception)
688
693
  $stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
689
694
  invoke(@main, :ip)
@@ -702,6 +707,10 @@ OUT
702
707
  Shelly::App.stub(:new).and_return(@app)
703
708
  end
704
709
 
710
+ it "should ensure user has logged in" do
711
+ hooks(@main, :delete).should include(:logged_in?)
712
+ end
713
+
705
714
  context "when cloud is given" do
706
715
  before do
707
716
  File.open("Cloudfile", 'w') {|f|
@@ -758,8 +767,8 @@ OUT
758
767
  f.write("foo-staging:\n") }
759
768
  end
760
769
 
761
- it "should raise Client::APIError" do
762
- exception = Shelly::Client::APIError.new(404)
770
+ it "should raise Client::NotFoundException" do
771
+ exception = Shelly::Client::NotFoundException.new("resource" => "cloud")
763
772
  @app.stub(:delete).and_raise(exception)
764
773
  $stdout.should_receive(:puts).with(red "You have no access to 'foo-bar' cloud defined in Cloudfile")
765
774
  lambda{
@@ -795,13 +804,46 @@ OUT
795
804
  end
796
805
  end
797
806
 
807
+ describe "#logout" do
808
+ before do
809
+ @user = Shelly::User.new
810
+ @client.stub(:token).and_return("abc")
811
+ Shelly::User.stub(:new).and_return(@user)
812
+ FileUtils.mkdir_p("~/.ssh")
813
+ FileUtils.mkdir_p("~/.shelly")
814
+ File.open("Cloudfile", 'w') { |f| f.write("foo-production:\n") }
815
+ File.open("~/.ssh/id_rsa.pub", "w") { |f| f << "ssh-key AAbbcc" }
816
+ @key_path = File.expand_path("~/.ssh/id_rsa.pub")
817
+ File.open("~/.shelly/credentials", "w") { |f| f << "megan@fox.pl\nsecret" }
818
+ @client.stub(:logout).and_return(true)
819
+ end
820
+
821
+ it "should ensure user has logged in" do
822
+ hooks(@main, :logout).should include(:logged_in?)
823
+ end
824
+
825
+ it "should logout from shelly cloud and show message" do
826
+ $stdout.should_receive(:puts).with("Your public SSH key has been removed from Shelly Cloud")
827
+ $stdout.should_receive(:puts).with("You have been successfully logged out")
828
+ invoke(@main, :logout)
829
+ File.exists?("~/.shelly/credentials").should be_false
830
+ end
831
+
832
+ it "should remove only credentiales when local ssh key doesn't exist" do
833
+ FileUtils.rm_rf(@key_path)
834
+ $stdout.should_receive(:puts).with("You have been successfully logged out")
835
+ invoke(@main, :logout)
836
+ File.exists?("~/.shelly/credentials").should be_false
837
+ end
838
+ end
839
+
798
840
  describe "#logs" do
799
841
  before do
800
842
  @user = Shelly::User.new
801
843
  @client.stub(:token).and_return("abc")
802
844
  FileUtils.mkdir_p("/projects/foo")
803
845
  Dir.chdir("/projects/foo")
804
- File.open("Cloudfile", 'w') {|f| f.write("foo-production:\n") }
846
+ File.open("Cloudfile", 'w') { |f| f.write("foo-production:\n") }
805
847
  Shelly::User.stub(:new).and_return(@user)
806
848
  @client.stub(:apps).and_return([{"code_name" => "foo-production"},
807
849
  {"code_name" => "foo-staging"}])
@@ -809,29 +851,19 @@ OUT
809
851
  Shelly::App.stub(:new).and_return(@app)
810
852
  end
811
853
 
812
- it "should exit if there is no Cloudfile" do
813
- File.delete("Cloudfile")
814
- $stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
815
- lambda {
816
- invoke(@main, :logs)
817
- }.should raise_error(SystemExit)
854
+ it "should ensure user has logged in" do
855
+ hooks(@main, :logs).should include(:logged_in?)
818
856
  end
819
857
 
820
- it "should exit if user doesn't have access to clouds in Cloudfile" do
821
- response = {"message" => "Cloud foo-production not found"}
822
- exception = Shelly::Client::APIError.new(404, response)
823
- @client.stub(:application_logs).and_raise(exception)
824
- $stdout.should_receive(:puts).
825
- with(red "You have no access to cloud 'foo-production'")
826
- lambda { invoke(@main, :logs) }.should raise_error(SystemExit)
858
+ it "should ensure that Cloudfile is present" do
859
+ hooks(@main, :logs).should include(:cloudfile_present?)
827
860
  end
828
861
 
829
- it "should exit if user is not logged in" do
830
- exception = Shelly::Client::APIError.new(401)
831
- @client.stub(:token).and_raise(exception)
862
+ it "should exit if user doesn't have access to clouds in Cloudfile" do
863
+ exception = Shelly::Client::NotFoundException.new("resource" => "cloud")
864
+ @client.stub(:application_logs).and_raise(exception)
832
865
  $stdout.should_receive(:puts).
833
- with(red "You are not logged in. To log in use:")
834
- $stdout.should_receive(:puts).with(" shelly login")
866
+ with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
835
867
  lambda { invoke(@main, :logs) }.should raise_error(SystemExit)
836
868
  end
837
869
 
@@ -852,9 +884,8 @@ OUT
852
884
  end
853
885
 
854
886
  it "should show information to print logs for specific cloud and exit" do
855
- $stdout.should_receive(:puts).
856
- with("You have multiple clouds in Cloudfile. Select which to show logs for using:")
857
- $stdout.should_receive(:puts).with(" shelly logs --cloud foo-production")
887
+ $stdout.should_receive(:puts).with(red "You have multiple clouds in Cloudfile.")
888
+ $stdout.should_receive(:puts).with("Select cloud using `shelly logs --cloud foo-production`")
858
889
  $stdout.should_receive(:puts).with("Available clouds:")
859
890
  $stdout.should_receive(:puts).with(" * foo-production")
860
891
  $stdout.should_receive(:puts).with(" * foo-staging")
@@ -884,4 +915,81 @@ OUT
884
915
  end
885
916
  end
886
917
  end
918
+
919
+ describe "#redeploy" do
920
+ before do
921
+ @user = Shelly::User.new
922
+ @client.stub(:token).and_return("abc")
923
+ @app = Shelly::App.new
924
+ Shelly::App.stub(:new).and_return(@app)
925
+ FileUtils.mkdir_p("/projects/foo")
926
+ Dir.chdir("/projects/foo")
927
+ File.open("Cloudfile", 'w') { |f| f.write("foo-production:\n") }
928
+ end
929
+
930
+ it "should redeploy the application" do
931
+ $stdout.should_receive(:puts).with(green "Redeploying your application for cloud 'foo-production'")
932
+ @app.should_receive(:redeploy)
933
+ invoke(@main, :redeploy)
934
+ end
935
+
936
+ context "on redeploy failure" do
937
+ %w(deploying configuring).each do |state|
938
+ context "when application is in #{state} state" do
939
+ it "should display error that deploy is in progress" do
940
+ exception = Shelly::Client::ConflictException.new("state" => state)
941
+ @client.should_receive(:redeploy).with("foo-production").and_raise(exception)
942
+ $stdout.should_receive(:puts).with(red "Your application is being redeployed at the moment")
943
+ lambda {
944
+ invoke(@main, :redeploy)
945
+ }.should raise_error(SystemExit)
946
+ end
947
+ end
948
+ end
949
+
950
+ %w(no_code no_billing turned_off).each do |state|
951
+ context "when application is in #{state} state" do
952
+ it "should display error that cloud is not running" do
953
+ exception = Shelly::Client::ConflictException.new("state" => state)
954
+ @client.should_receive(:redeploy).with("foo-production").and_raise(exception)
955
+ $stdout.should_receive(:puts).with(red "Cloud foo-production is not running")
956
+ $stdout.should_receive(:puts).with("Start your cloud with `shelly start --cloud foo-production`")
957
+ lambda {
958
+ invoke(@main, :redeploy)
959
+ }.should raise_error(SystemExit)
960
+ end
961
+ end
962
+ end
963
+
964
+ it "should re-raise exception on unknown state" do
965
+ exception = Shelly::Client::ConflictException.new("state" => "doing_something")
966
+ @client.should_receive(:redeploy).with("foo-production").and_raise(exception)
967
+ lambda {
968
+ invoke(@main, :redeploy)
969
+ }.should raise_error(Shelly::Client::ConflictException)
970
+ end
971
+ end
972
+
973
+ context "on multiple clouds in Cloudfile" do
974
+ before do
975
+ File.open("Cloudfile", 'w') { |f| f.write("foo-staging:\nfoo-production:\n") }
976
+ end
977
+
978
+ it "should show information to redeploy application for specific cloud and exit" do
979
+ $stdout.should_receive(:puts).with(red "You have multiple clouds in Cloudfile.")
980
+ $stdout.should_receive(:puts).with("Select cloud using `shelly redeploy --cloud foo-production`")
981
+ $stdout.should_receive(:puts).with("Available clouds:")
982
+ $stdout.should_receive(:puts).with(" * foo-production")
983
+ $stdout.should_receive(:puts).with(" * foo-staging")
984
+ lambda { invoke(@main, :redeploy) }.should raise_error(SystemExit)
985
+ end
986
+
987
+ it "should fetch from command line which cloud to redeploy application for" do
988
+ @client.should_receive(:redeploy).with("foo-staging")
989
+ $stdout.should_receive(:puts).with(green "Redeploying your application for cloud 'foo-staging'")
990
+ @main.options = {:cloud => "foo-staging"}
991
+ invoke(@main, :redeploy)
992
+ end
993
+ end
994
+ end
887
995
  end
@@ -22,7 +22,7 @@ describe Shelly::CLI::Runner do
22
22
  it "should be true if args include --debug option" do
23
23
  @runner.should be_debug
24
24
  end
25
-
25
+
26
26
  it "should be true if SHELLY_DEBUG is set to true" do
27
27
  runner = Shelly::CLI::Runner.new
28
28
  runner.should_not be_debug
@@ -42,6 +42,16 @@ describe Shelly::CLI::Runner do
42
42
  @runner.start
43
43
  end
44
44
 
45
+ it "should rescue interrupt exception and display message" do
46
+ Shelly::CLI::Main.stub(:start).and_raise(Interrupt.new)
47
+ runner = Shelly::CLI::Runner.new(%w(login))
48
+ $stdout.should_receive(:puts).with("\n")
49
+ $stdout.should_receive(:puts).with("[canceled]")
50
+ lambda {
51
+ runner.start
52
+ }.should raise_error(SystemExit)
53
+ end
54
+
45
55
  context "with --debug option (debug mode)" do
46
56
  it "should re-raise caught exception to the console" do
47
57
  Shelly::CLI::Main.stub(:start).and_raise(RuntimeError.new)
@@ -60,6 +70,24 @@ describe Shelly::CLI::Runner do
60
70
  runner.start
61
71
  }.should raise_error(SystemExit)
62
72
  end
73
+
74
+ it "should caught exception thrown by API Client" do
75
+ Shelly::CLI::Main.stub(:start).and_raise(Shelly::Client::APIException.new)
76
+ runner = Shelly::CLI::Runner.new(%w(version))
77
+ $stdout.should_receive(:puts).with("Unknown error, to see debug information run command with --debug")
78
+ lambda {
79
+ runner.start
80
+ }.should raise_error(SystemExit)
81
+ end
82
+
83
+ it "should re-reise SystemExit exceptions" do
84
+ Shelly::CLI::Main.stub(:start).and_raise(SystemExit.new)
85
+ $stdout.should_not_receive(:puts).with("Unknown error, to see debug information run command with --debug")
86
+ runner = Shelly::CLI::Runner.new(%w(version))
87
+ lambda {
88
+ runner.start
89
+ }.should raise_error(SystemExit)
90
+ end
63
91
  end
64
92
  end
65
93
  end