vmc 0.5.0.rc1 → 0.5.0.rc2
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/lib/vmc/cli.rb +2 -1
- data/lib/vmc/cli/app/start.rb +81 -24
- data/lib/vmc/cli/space/create.rb +4 -0
- data/lib/vmc/cli/space/switch.rb +16 -0
- data/lib/vmc/cli/start/base.rb +21 -18
- data/lib/vmc/cli/user/base.rb +1 -1
- data/lib/vmc/cli/user/delete.rb +2 -0
- data/lib/vmc/version.rb +1 -1
- data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
- data/spec/features/{new_user_flow_spec.rb → v1/new_user_flow_spec.rb} +12 -18
- data/spec/features/v2/account_lifecycle_spec.rb +64 -0
- data/spec/features/v2/push_flow_spec.rb +126 -0
- data/spec/spec_helper.rb +16 -3
- data/{lib/vmc/test_support → spec/support}/command_helper.rb +5 -5
- data/spec/support/config_helper.rb +15 -0
- data/spec/support/console_app_specker_matchers.rb +2 -2
- data/spec/support/fake_home_dir.rb +42 -0
- data/{lib/vmc/test_support → spec/support}/interact_helper.rb +1 -1
- data/spec/support/shared_examples/errors.rb +40 -0
- data/{lib/vmc/test_support/common_input_examples.rb → spec/support/shared_examples/input.rb} +0 -0
- data/spec/support/specker_runner.rb +17 -61
- data/spec/support/tracking_expector.rb +71 -0
- data/spec/vmc/cli/app/instances_spec.rb +3 -3
- data/spec/vmc/cli/app/start_spec.rb +201 -0
- data/spec/vmc/cli/app/stats_spec.rb +21 -15
- data/spec/vmc/cli/space/create_spec.rb +73 -0
- data/spec/vmc/cli/space/switch_space_spec.rb +55 -0
- data/spec/vmc/cli/start/info_spec.rb +3 -16
- data/spec/vmc/cli/start/login_spec.rb +97 -37
- data/spec/vmc/cli/start/logout_spec.rb +3 -16
- data/spec/vmc/cli/start/target_spec.rb +84 -0
- data/spec/vmc/cli/user/delete_spec.rb +51 -0
- data/spec/vmc/cli/user/passwd_spec.rb +1 -1
- data/spec/vmc/cli/user/register_spec.rb +1 -1
- data/spec/vmc/cli_spec.rb +38 -36
- metadata +65 -39
- data/lib/vmc/cli/space/take.rb +0 -16
- data/lib/vmc/test_support/fake_home_dir.rb +0 -16
@@ -3,7 +3,7 @@ require 'stringio'
|
|
3
3
|
|
4
4
|
describe VMC::App::Stats do
|
5
5
|
let(:global) { { :color => false } }
|
6
|
-
let(:inputs) { {:app => apps[0]} }
|
6
|
+
let(:inputs) { { :app => apps[0] } }
|
7
7
|
let(:given) { {} }
|
8
8
|
let(:client) { fake_client(:apps => apps) }
|
9
9
|
let(:apps) { [fake(:app, :name => "basic_app")] }
|
@@ -13,21 +13,27 @@ describe VMC::App::Stats do
|
|
13
13
|
stub(cli).client { client }
|
14
14
|
stub(cli).precondition { nil }
|
15
15
|
end
|
16
|
-
stub(
|
17
|
-
{"0" => {
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
16
|
+
stub(inputs[:app]).stats do
|
17
|
+
{ "0" => {
|
18
|
+
:state => "RUNNING",
|
19
|
+
:stats => {
|
20
|
+
:name => "basic_app",
|
21
|
+
:uris => ["basic_app.p01.rbconsvcs.com"],
|
22
|
+
:host => "172.20.183.93",
|
23
|
+
:port => 61006,
|
24
|
+
:uptime => 3250,
|
25
|
+
:mem_quota => 301989888,
|
26
|
+
:disk_quota => 268435456,
|
27
|
+
:fds_quota => 256,
|
28
|
+
:usage => {
|
29
|
+
:time => "2013-01-04 19:53:39 +0000",
|
30
|
+
:cpu => 0.0019777013519415455,
|
31
|
+
:mem => 31395840,
|
32
|
+
:disk => 15638528
|
33
|
+
}
|
34
|
+
}
|
29
35
|
}
|
30
|
-
}
|
36
|
+
}
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "vmc/cli/space/create"
|
3
|
+
|
4
|
+
describe VMC::Space::Create do
|
5
|
+
let(:spaces) { fake_list(:space, 3) }
|
6
|
+
let(:organization) { fake(:organization, :spaces => spaces) }
|
7
|
+
let(:new_space) { stub! }
|
8
|
+
let(:client) { fake_client(:current_organization => organization, :spaces => spaces) }
|
9
|
+
let(:new_name) { "some-new-name" }
|
10
|
+
|
11
|
+
before do
|
12
|
+
%w{create! organization= name= name add_manager add_developer add_auditor organization}.each do |method|
|
13
|
+
new_space.__send__(method.to_sym)
|
14
|
+
end
|
15
|
+
|
16
|
+
stub(client).space { new_space }
|
17
|
+
any_instance_of described_class do |cli|
|
18
|
+
stub(cli).client { client }
|
19
|
+
stub(cli).precondition { nil }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'metadata' do
|
24
|
+
let(:command) { Mothership.commands[:create_space] }
|
25
|
+
|
26
|
+
describe 'command' do
|
27
|
+
subject { command }
|
28
|
+
its(:description) { should eq "Create a space in an organization" }
|
29
|
+
it { expect(Mothership::Help.group(:spaces)).to include(subject) }
|
30
|
+
end
|
31
|
+
|
32
|
+
include_examples 'inputs must have descriptions'
|
33
|
+
|
34
|
+
describe 'arguments' do
|
35
|
+
subject { command.arguments }
|
36
|
+
it 'has the correct argument order' do
|
37
|
+
should eq([
|
38
|
+
{ :type => :optional, :value => nil, :name => :name },
|
39
|
+
{ :type => :optional, :value => nil, :name => :organization }
|
40
|
+
])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when we don't specify an organization" do
|
46
|
+
subject { vmc %W[--no-quiet create-space new-space-name] }
|
47
|
+
|
48
|
+
context "when we have a default organization" do
|
49
|
+
it "uses that organization to create a space" do
|
50
|
+
subject
|
51
|
+
|
52
|
+
stdout.rewind
|
53
|
+
expect(stdout.readline).to include "Creating space"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when we don't have a default organization" do
|
58
|
+
let(:organization) { nil }
|
59
|
+
|
60
|
+
it "shows the help for the command" do
|
61
|
+
subject
|
62
|
+
|
63
|
+
stdout.rewind
|
64
|
+
expect(stdout.readline).to include "Create a space in an organization"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "does not try to create the space" do
|
68
|
+
new_space.create! { raise "should not call this method" } # rr not behaving
|
69
|
+
subject
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "vmc/cli/space/switch"
|
3
|
+
|
4
|
+
describe VMC::Space::Switch do
|
5
|
+
let(:space_to_switch_to) { spaces.last }
|
6
|
+
let(:spaces) { fake_list(:space, 3) }
|
7
|
+
let(:organization) { fake(:organization, :spaces => spaces) }
|
8
|
+
let(:client) { fake_client(:current_organization => organization, :spaces => spaces) }
|
9
|
+
|
10
|
+
before do
|
11
|
+
any_instance_of described_class do |cli|
|
12
|
+
stub(cli).client { client }
|
13
|
+
stub(cli).precondition { nil }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'metadata' do
|
18
|
+
let(:command) { Mothership.commands[:switch_space] }
|
19
|
+
|
20
|
+
describe 'command' do
|
21
|
+
subject { command }
|
22
|
+
its(:description) { should eq "Switch to a space" }
|
23
|
+
it { expect(Mothership::Help.group(:spaces)).to include(subject) }
|
24
|
+
end
|
25
|
+
|
26
|
+
include_examples 'inputs must have descriptions'
|
27
|
+
|
28
|
+
describe 'arguments' do
|
29
|
+
subject { command.arguments }
|
30
|
+
it 'has the correct argument order' do
|
31
|
+
should eq([{ :type => :normal, :value => nil, :name => :name }])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
subject { vmc %W[--no-quiet switch-space #{space_to_switch_to.name} --no-color] }
|
37
|
+
|
38
|
+
context "when the space exists" do
|
39
|
+
it "switches to that space" do
|
40
|
+
any_instance_of(Mothership) do |m|
|
41
|
+
mock(m).invoke(:target, {:space => space_to_switch_to})
|
42
|
+
end
|
43
|
+
|
44
|
+
subject
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when the space does not exist" do
|
49
|
+
let(:space_to_switch_to) { fake(:space, :name => "unique-name") }
|
50
|
+
|
51
|
+
it_behaves_like "an error that gets passed through",
|
52
|
+
:with_exception => VMC::UserError,
|
53
|
+
:with_message => "The space unique-name does not exist, please create the space first."
|
54
|
+
end
|
55
|
+
end
|
@@ -24,18 +24,6 @@ describe VMC::Start::Info do
|
|
24
24
|
any_instance_of described_class do |cli|
|
25
25
|
stub(cli).client { client }
|
26
26
|
end
|
27
|
-
|
28
|
-
described_class.class_eval do
|
29
|
-
def wrap_errors
|
30
|
-
yield
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
after do
|
36
|
-
described_class.class_eval do
|
37
|
-
remove_method :wrap_errors
|
38
|
-
end
|
39
27
|
end
|
40
28
|
|
41
29
|
describe 'metadata' do
|
@@ -165,9 +153,8 @@ describe VMC::Start::Info do
|
|
165
153
|
|
166
154
|
context 'when there is no target' do
|
167
155
|
let(:client) { nil }
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
156
|
+
it_behaves_like "an error that gets passed through",
|
157
|
+
:with_exception => VMC::UserError,
|
158
|
+
:with_message => "Please select a target with 'vmc target'."
|
172
159
|
end
|
173
160
|
end
|
@@ -7,18 +7,6 @@ describe VMC::Start::Login do
|
|
7
7
|
any_instance_of described_class do |cli|
|
8
8
|
stub(cli).client { client }
|
9
9
|
end
|
10
|
-
|
11
|
-
described_class.class_eval do
|
12
|
-
def wrap_errors
|
13
|
-
yield
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
after do
|
19
|
-
described_class.class_eval do
|
20
|
-
remove_method :wrap_errors
|
21
|
-
end
|
22
10
|
end
|
23
11
|
|
24
12
|
describe 'metadata' do
|
@@ -27,7 +15,7 @@ describe VMC::Start::Login do
|
|
27
15
|
describe 'command' do
|
28
16
|
subject { command }
|
29
17
|
its(:description) { should eq "Authenticate with the target" }
|
30
|
-
|
18
|
+
specify { expect(Mothership::Help.group(:start)).to include(subject) }
|
31
19
|
end
|
32
20
|
|
33
21
|
include_examples 'inputs must have descriptions'
|
@@ -42,34 +30,31 @@ describe VMC::Start::Login do
|
|
42
30
|
end
|
43
31
|
|
44
32
|
describe 'arguments' do
|
45
|
-
subject { command.arguments }
|
33
|
+
subject(:arguments) { command.arguments }
|
46
34
|
it 'have the correct commands' do
|
47
|
-
|
35
|
+
expect(arguments).to eq [{:type => :optional, :value => :email, :name => :username}]
|
48
36
|
end
|
49
37
|
end
|
50
38
|
end
|
51
39
|
|
52
40
|
describe "running the command" do
|
53
|
-
|
54
|
-
|
55
|
-
let(:home_dir) do
|
56
|
-
tmp_root = Dir.tmpdir
|
57
|
-
FileUtils.cp_r(File.expand_path("#{SPEC_ROOT}/fixtures/fake_home_dirs/new"), tmp_root)
|
58
|
-
"#{tmp_root}/new"
|
59
|
-
end
|
41
|
+
stub_home_dir_with("new")
|
60
42
|
|
61
43
|
let(:auth_token) { CFoundry::AuthToken.new("bearer some-new-access-token", "some-new-refresh-token") }
|
62
|
-
|
63
|
-
|
44
|
+
let(:tokens_yaml) { YAML.load_file(File.expand_path(tokens_file_path)) }
|
45
|
+
let(:tokens_file_path) { '~/.vmc/tokens.yml' }
|
46
|
+
let(:organizations) { [] }
|
64
47
|
|
65
48
|
before do
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
49
|
+
any_instance_of(CFoundry::V2::Client) do |client|
|
50
|
+
stub(client).login("my-username", "my-password") { auth_token }
|
51
|
+
stub(client).login_prompts do
|
52
|
+
{
|
53
|
+
:username => ["text", "Username"],
|
54
|
+
:password => ["password", "8-digit PIN"]
|
55
|
+
}
|
56
|
+
end
|
57
|
+
stub(client).organizations { [] }
|
73
58
|
end
|
74
59
|
end
|
75
60
|
|
@@ -77,21 +62,96 @@ describe VMC::Start::Login do
|
|
77
62
|
|
78
63
|
it "logs in with the provided credentials and saves the token data to the YAML file" do
|
79
64
|
stub_ask("Username", {}) { "my-username" }
|
80
|
-
stub_ask("8-digit PIN", {
|
65
|
+
stub_ask("8-digit PIN", {:echo => "*", :forget => true}) { "my-password" }
|
81
66
|
|
82
67
|
subject
|
83
68
|
|
84
|
-
tokens_yaml = YAML.load_file(File.expand_path("~/.vmc/tokens.yml"))
|
85
69
|
expect(tokens_yaml["https://api.some-domain.com"][:token]).to eq("bearer some-new-access-token")
|
86
70
|
expect(tokens_yaml["https://api.some-domain.com"][:refresh_token]).to eq("some-new-refresh-token")
|
87
71
|
end
|
88
72
|
|
89
|
-
context
|
90
|
-
|
73
|
+
context "with space and org in the token file" do
|
74
|
+
before do
|
75
|
+
write_token_file({:space => "space-id-1", :organization => "organization-id-1"})
|
76
|
+
stub_ask("Username", {}) { "my-username" }
|
77
|
+
stub_ask("8-digit PIN", {:echo => "*", :forget => true}) { "my-password" }
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when the user has no organizations" do
|
81
|
+
it "clears the org and space param from the token file" do
|
82
|
+
subject
|
83
|
+
|
84
|
+
expect(tokens_yaml["https://api.some-domain.com"][:space]).to be_nil
|
85
|
+
expect(tokens_yaml["https://api.some-domain.com"][:organization]).to be_nil
|
86
|
+
end
|
87
|
+
end
|
91
88
|
|
92
|
-
|
93
|
-
|
89
|
+
context "when the user has an organization, but no spaces" do
|
90
|
+
before do
|
91
|
+
stub.proxy(client).organization { organization }
|
92
|
+
any_instance_of(described_class) do |instance|
|
93
|
+
stub(instance).client { client }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
let(:client) { fake_client :organizations => organizations,
|
98
|
+
:token => CFoundry::AuthToken.new("bearer some-access-token") }
|
99
|
+
let(:organization) { OpenStruct.new(:name => 'My Org', :guid => 'organization-id-1', :users => [user]) }
|
100
|
+
let(:user) { stub }
|
101
|
+
|
102
|
+
before do
|
103
|
+
stub(organization).spaces { [] }
|
104
|
+
end
|
105
|
+
|
106
|
+
shared_examples_for :method_clearing_the_token_file do
|
107
|
+
it "sets the new organization in the token file" do
|
108
|
+
subject
|
109
|
+
expect(tokens_yaml["https://api.some-domain.com"][:organization]).to eq(organizations.first.guid)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "clears the space param from the token file" do
|
113
|
+
subject
|
114
|
+
expect(tokens_yaml["https://api.some-domain.com"][:space]).to be_nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "with one organization" do
|
119
|
+
let(:organizations) {
|
120
|
+
[ organization ]
|
121
|
+
}
|
122
|
+
|
123
|
+
it "does not prompt for an organization" do
|
124
|
+
dont_allow_ask("Organization", anything)
|
125
|
+
subject
|
126
|
+
end
|
127
|
+
|
128
|
+
it_behaves_like :method_clearing_the_token_file
|
129
|
+
end
|
130
|
+
|
131
|
+
context "with multiple organizations" do
|
132
|
+
let(:organizations) {
|
133
|
+
[ organization, OpenStruct.new(:name => 'My Org 2', :guid => 'organization-id-2') ]
|
134
|
+
}
|
135
|
+
|
136
|
+
before do
|
137
|
+
stub_ask("Organization", anything) { organizations.first }
|
138
|
+
end
|
139
|
+
|
140
|
+
it "prompts for organization" do
|
141
|
+
mock_ask("Organization", anything) { organizations.first }
|
142
|
+
subject
|
143
|
+
end
|
144
|
+
|
145
|
+
it_behaves_like :method_clearing_the_token_file
|
146
|
+
end
|
94
147
|
end
|
95
148
|
end
|
149
|
+
|
150
|
+
context 'when there is no target' do
|
151
|
+
let(:client) { nil }
|
152
|
+
it_behaves_like "an error that gets passed through",
|
153
|
+
:with_exception => VMC::UserError,
|
154
|
+
:with_message => "Please select a target with 'vmc target'."
|
155
|
+
end
|
96
156
|
end
|
97
157
|
end
|
@@ -7,18 +7,6 @@ describe VMC::Start::Logout do
|
|
7
7
|
any_instance_of described_class do |cli|
|
8
8
|
stub(cli).client { client }
|
9
9
|
end
|
10
|
-
|
11
|
-
described_class.class_eval do
|
12
|
-
def wrap_errors
|
13
|
-
yield
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
after do
|
19
|
-
described_class.class_eval do
|
20
|
-
remove_method :wrap_errors
|
21
|
-
end
|
22
10
|
end
|
23
11
|
|
24
12
|
describe 'metadata' do
|
@@ -53,10 +41,9 @@ describe VMC::Start::Logout do
|
|
53
41
|
|
54
42
|
context "when there is no target" do
|
55
43
|
let(:client) { nil }
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
44
|
+
it_behaves_like "an error that gets passed through",
|
45
|
+
:with_exception => VMC::UserError,
|
46
|
+
:with_message => "Please select a target with 'vmc target'."
|
60
47
|
end
|
61
48
|
end
|
62
49
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VMC::Start::Target do
|
4
|
+
describe 'metadata' do
|
5
|
+
let(:command) { Mothership.commands[:target] }
|
6
|
+
|
7
|
+
describe 'command' do
|
8
|
+
subject { command }
|
9
|
+
its(:description) { should eq "Set or display the target cloud, organization, and space" }
|
10
|
+
specify { expect(Mothership::Help.group(:start)).to include(subject) }
|
11
|
+
end
|
12
|
+
|
13
|
+
include_examples 'inputs must have descriptions'
|
14
|
+
|
15
|
+
describe 'flags' do
|
16
|
+
subject { command.flags }
|
17
|
+
|
18
|
+
its(["-o"]) { should eq :organization }
|
19
|
+
its(["--org"]) { should eq :organization }
|
20
|
+
its(["-s"]) { should eq :space }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'arguments' do
|
24
|
+
subject(:arguments) { command.arguments }
|
25
|
+
it 'have the correct commands' do
|
26
|
+
expect(arguments).to eq [{:type => :optional, :value => nil, :name => :url}]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'running the command' do
|
32
|
+
stub_home_dir_with("new")
|
33
|
+
|
34
|
+
context "when the user is authenticated and has an organization" do
|
35
|
+
let(:tokens_file_path) { '~/.vmc/tokens.yml' }
|
36
|
+
let(:organizations) {
|
37
|
+
[ fake(:organization, :name => 'My Org', :guid => 'organization-id-1', :users => [user], :spaces => spaces),
|
38
|
+
fake(:organization, :name => 'My Org 2', :guid => 'organization-id-2') ]
|
39
|
+
}
|
40
|
+
let(:spaces) {
|
41
|
+
[ fake(:space, :name => 'Development', :guid => 'space-id-1'),
|
42
|
+
fake(:space, :name => 'Staging', :guid => 'space-id-2') ]
|
43
|
+
}
|
44
|
+
|
45
|
+
let(:user) { stub! }
|
46
|
+
let(:organization) { organizations.first }
|
47
|
+
let(:client) do
|
48
|
+
fake_client :frameworks => fake_list(:framework, 3),
|
49
|
+
:organizations => organizations,
|
50
|
+
:token => CFoundry::AuthToken.new("bearer some-access-token")
|
51
|
+
end
|
52
|
+
|
53
|
+
before do
|
54
|
+
write_token_file({:space => "space-id-1", :organization => "organization-id-1"})
|
55
|
+
stub(client).current_user { user }
|
56
|
+
stub(client).organization { organization }
|
57
|
+
stub(client).current_organization { organization }
|
58
|
+
any_instance_of(described_class) do |instance|
|
59
|
+
stub(instance).client { client }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "switching the space" do
|
64
|
+
let(:space_name) { spaces.last.name }
|
65
|
+
let(:tokens_yaml) { YAML.load_file(File.expand_path(tokens_file_path)) }
|
66
|
+
let(:tokens_file_path) { '~/.vmc/tokens.yml' }
|
67
|
+
|
68
|
+
def run_command
|
69
|
+
vmc ["target", "-s", space_name]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not reprompt for organization" do
|
73
|
+
dont_allow_ask("Organization", anything)
|
74
|
+
run_command
|
75
|
+
end
|
76
|
+
|
77
|
+
it "sets the space param in the token file" do
|
78
|
+
run_command
|
79
|
+
expect(tokens_yaml["https://api.some-domain.com"][:space]).to be == 'space-id-2'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|