dew 0.1.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/LICENSE +22 -0
- data/README.md +38 -0
- data/Rakefile +26 -0
- data/bin/dew +87 -0
- data/config/cucumber.yaml +4 -0
- data/features/create-ami.feature +16 -0
- data/features/create-environments.feature +46 -0
- data/features/deploy-puge.feature +16 -0
- data/features/step_definitions/aws-steps.rb +101 -0
- data/features/step_definitions/deploy-puge-steps.rb +27 -0
- data/features/support/env.rb +38 -0
- data/features/support/hooks.rb +10 -0
- data/lib/dew.rb +7 -0
- data/lib/dew/aws_resources.yaml +122 -0
- data/lib/dew/base_command.rb +24 -0
- data/lib/dew/cloud.rb +79 -0
- data/lib/dew/commands.rb +6 -0
- data/lib/dew/commands/ami.rb +67 -0
- data/lib/dew/commands/console.rb +17 -0
- data/lib/dew/commands/console/irb_override.rb +24 -0
- data/lib/dew/commands/deploy.rb +114 -0
- data/lib/dew/commands/deploy/templates/apache.conf.erb +28 -0
- data/lib/dew/commands/deploy/templates/known_hosts +2 -0
- data/lib/dew/commands/deploy/templates/rvmrc +2 -0
- data/lib/dew/commands/environments.rb +110 -0
- data/lib/dew/commands/tidy.rb +35 -0
- data/lib/dew/controllers.rb +3 -0
- data/lib/dew/controllers/amis_controller.rb +82 -0
- data/lib/dew/controllers/deploy_controller.rb +10 -0
- data/lib/dew/controllers/environments_controller.rb +48 -0
- data/lib/dew/models.rb +7 -0
- data/lib/dew/models/account.rb +30 -0
- data/lib/dew/models/database.rb +32 -0
- data/lib/dew/models/deploy.rb +2 -0
- data/lib/dew/models/deploy/puge.rb +61 -0
- data/lib/dew/models/deploy/run.rb +19 -0
- data/lib/dew/models/environment.rb +199 -0
- data/lib/dew/models/fog_model.rb +23 -0
- data/lib/dew/models/profile.rb +60 -0
- data/lib/dew/models/server.rb +134 -0
- data/lib/dew/password.rb +7 -0
- data/lib/dew/tasks/spec.rake +14 -0
- data/lib/dew/validations.rb +8 -0
- data/lib/dew/version.rb +3 -0
- data/lib/dew/view.rb +39 -0
- data/lib/tasks/spec.rake +14 -0
- data/spec/dew/cloud_spec.rb +90 -0
- data/spec/dew/controllers/amis_controller_spec.rb +137 -0
- data/spec/dew/controllers/deploy_controller_spec.rb +38 -0
- data/spec/dew/controllers/environments_controller_spec.rb +133 -0
- data/spec/dew/models/account_spec.rb +47 -0
- data/spec/dew/models/database_spec.rb +58 -0
- data/spec/dew/models/deploy/puge_spec.rb +72 -0
- data/spec/dew/models/deploy/run_spec.rb +38 -0
- data/spec/dew/models/environment_spec.rb +374 -0
- data/spec/dew/models/fog_model_spec.rb +24 -0
- data/spec/dew/models/profile_spec.rb +85 -0
- data/spec/dew/models/server_spec.rb +190 -0
- data/spec/dew/password_spec.rb +11 -0
- data/spec/dew/spec_helper.rb +22 -0
- data/spec/dew/view_spec.rb +38 -0
- metadata +284 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
4
|
+
t.pattern = "./spec/**/*_spec.rb"
|
5
|
+
# Put spec opts in a file named .rspec in root
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :spec do
|
9
|
+
desc "Run tests with coverage check"
|
10
|
+
task :covered do
|
11
|
+
ENV['RSPEC_COVERED'] = '1'
|
12
|
+
Rake::Task['spec'].execute
|
13
|
+
end
|
14
|
+
end
|
data/lib/dew/version.rb
ADDED
data/lib/dew/view.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'terminal-table/import'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def indent(n)
|
5
|
+
if n >= 0
|
6
|
+
gsub(/^/, ' ' * n)
|
7
|
+
else
|
8
|
+
gsub(/^ {0,#{-n}}/, "")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
class View
|
15
|
+
def initialize(name, items, keys)
|
16
|
+
@name = name
|
17
|
+
@items = items
|
18
|
+
@keys = keys
|
19
|
+
end
|
20
|
+
|
21
|
+
def index
|
22
|
+
rows = @items.collect { |item| collect_values(item) }
|
23
|
+
"#{@name}:\n#{rows.empty? ? "None\n".indent(2) : table(@keys, *rows).to_s.indent(2)}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def show(i)
|
27
|
+
"#{@name}:\n" +
|
28
|
+
table(nil, *@keys.collect { |item| item }.zip( collect_values(@items[i]))).to_s.indent(2)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def collect_values(item)
|
33
|
+
@keys.collect { |key|
|
34
|
+
v = item.is_a?(Hash) ? (item.has_key?(key) && item.fetch(key) || item.has_key?(key.to_sym) && item.fetch(key.to_sym)) : item.send(key)
|
35
|
+
v.inspect
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
data/lib/tasks/spec.rake
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
4
|
+
t.pattern = "./spec/**/*_spec.rb"
|
5
|
+
# Put spec opts in a file named .rspec in root
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :spec do
|
9
|
+
desc "Run tests with coverage check"
|
10
|
+
task :covered do
|
11
|
+
ENV['RSPEC_COVERED'] = '1'
|
12
|
+
Rake::Task['spec'].execute
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
describe :Cloud do
|
4
|
+
|
5
|
+
let (:region) { 'ap-southeast-1' }
|
6
|
+
let (:account_name) { 'development' }
|
7
|
+
let (:profile_name) { 'test-light' }
|
8
|
+
|
9
|
+
let (:aws_credentials) { {:aws_access_key_id => '1234', :aws_secret_access_key => '5678', :region => region} }
|
10
|
+
let (:root_aws_credentials) { aws_credentials.merge(:provider => 'AWS')}
|
11
|
+
let (:account) { double('Account', aws_credentials) }
|
12
|
+
let (:profile) { double('Profile') }
|
13
|
+
|
14
|
+
context "after connect is called" do
|
15
|
+
before :each do
|
16
|
+
Account.stub(:read => account)
|
17
|
+
Cloud.connect(region, account_name, profile_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
it { Cloud.region.should == region }
|
21
|
+
it { Cloud.account_name.should == account_name }
|
22
|
+
it { Cloud.profile_name.should == profile_name }
|
23
|
+
|
24
|
+
it "should provide the Account" do
|
25
|
+
Account.should_receive(:read).with(account_name).and_return(account)
|
26
|
+
Cloud.account.should == account
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should provide the Profile" do
|
30
|
+
Profile.should_receive(:read).with(profile_name).and_return(profile)
|
31
|
+
Cloud.profile.should == profile
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should provide a compute hook" do
|
35
|
+
Fog::Compute.should_receive(:new).with(root_aws_credentials).and_return('compute')
|
36
|
+
Cloud.compute.should == 'compute'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should provide a security groups hook" do
|
40
|
+
security_group = double(:security_group, :name => 'foo')
|
41
|
+
Fog::Compute.should_receive(:new).with(root_aws_credentials).and_return(double(:compute, :security_groups => [security_group]))
|
42
|
+
Cloud.security_groups.should == { 'foo' => security_group }
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return valid servers" do
|
46
|
+
servers = [
|
47
|
+
double(:server, :state => 'running'),
|
48
|
+
double(:server, :state => 'terminated'),
|
49
|
+
double(:server, :state => 'pending')
|
50
|
+
]
|
51
|
+
Cloud.stub_chain(:compute, :servers).and_return( servers )
|
52
|
+
Cloud.valid_servers.should == [servers[0], servers[2]]
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should check AWS to ensure the given keypair exists" do
|
56
|
+
Fog::Compute.should_receive(:new).with(root_aws_credentials).and_return(
|
57
|
+
double(:compute, :key_pairs => mock(:some_key_pairs, :get => true))
|
58
|
+
)
|
59
|
+
Cloud.keypair_exists?('a_keypair').should be_true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should provide an ELB hook" do
|
63
|
+
Fog::AWS::ELB.should_receive(:new).with(aws_credentials).and_return('elb')
|
64
|
+
Cloud.elb.should == 'elb'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should provide an RDS hook" do
|
68
|
+
Fog::AWS::RDS.should_receive(:new).with(aws_credentials).and_return('rds')
|
69
|
+
Cloud.rds.should == 'rds'
|
70
|
+
end
|
71
|
+
|
72
|
+
# TODO: should this be here?
|
73
|
+
it "should provide a hook to the rds_authorized_ec2_owner_ids" do
|
74
|
+
Fog::AWS::RDS.should_receive(:new).with(aws_credentials).and_return(
|
75
|
+
double(:rds, :security_groups => [ double(:security_group, :id => 'default', :ec2_security_groups => [
|
76
|
+
{ "EC2SecurityGroupName" => "default", "Status" => "authorized", "EC2SecurityGroupOwnerId" => '12345' }
|
77
|
+
]) ])
|
78
|
+
)
|
79
|
+
Cloud.rds_authorized_ec2_owner_ids.should == ['12345']
|
80
|
+
end
|
81
|
+
|
82
|
+
describe :keyfile_path do
|
83
|
+
it "should look for the keypair in the ~/.dew/accounts directory" do
|
84
|
+
Cloud.connect(region, account_name)
|
85
|
+
Cloud.keyfile_path('devops').should == "#{ENV['HOME']}/.dew/accounts/keys/#{account_name}/#{region}/devops.pem"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe AMIsController do
|
4
|
+
|
5
|
+
let (:controller) { AMIsController.new }
|
6
|
+
let (:ami_name) { 'my-ami' }
|
7
|
+
let (:puppet_node_name) { 'puppet-node-name' }
|
8
|
+
let (:ssh) { double('SSH', :run => nil, :upload => nil) }
|
9
|
+
let (:server) { double('Server', :id => 'i-12345', :ssh => ssh, :public_ip_address => '127.0.0.1', :create_ami => nil) }
|
10
|
+
let (:environment) { double('Environment', :servers => [server], :destroy => nil) }
|
11
|
+
let (:ami) { double('AMI', :owner_id => '1234') }
|
12
|
+
let (:images) { double('ComputeImages') }
|
13
|
+
|
14
|
+
before { Cloud.stub(:compute => double('Compute', :images => images)) }
|
15
|
+
|
16
|
+
describe :create do
|
17
|
+
before :each do
|
18
|
+
Profile.stub(:read => nil)
|
19
|
+
Environment.stub(:create => environment)
|
20
|
+
end
|
21
|
+
after :each do
|
22
|
+
controller.create(ami_name, puppet_node_name)
|
23
|
+
end
|
24
|
+
it "should create a new environment using the ami-prototype profile" do
|
25
|
+
Profile.should_receive(:read).with('ami-prototype').and_return('ami_profile')
|
26
|
+
Environment.should_receive(:create).with(/#{ami_name}/, 'ami_profile').and_return environment
|
27
|
+
end
|
28
|
+
# Not all elements of the script are tested - just the important bits
|
29
|
+
it "should upload our puppet configuration to the instance" do
|
30
|
+
ssh.should_receive(:upload)#.with(File.join(ROOT_DIR, 'puppet'), '/tmp/puppet')
|
31
|
+
end
|
32
|
+
it "should run puppet using the node name we specified" do
|
33
|
+
ssh.should_receive(:run).with(%r{puppet.+/etc/puppet/manifests/nodes/#{puppet_node_name}.pp})
|
34
|
+
end
|
35
|
+
it "should create an AMI from the resulting server" do
|
36
|
+
server.should_receive(:create_ami).with(ami_name)
|
37
|
+
end
|
38
|
+
it "should finally destroy the environment" do
|
39
|
+
environment.should_receive(:destroy)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe :index do
|
44
|
+
before { images.stub(:all => [ami]) }
|
45
|
+
after { controller.index }
|
46
|
+
|
47
|
+
it "should show an index of the amis" do
|
48
|
+
Cloud.should_receive(:account).at_least(1).and_return(double(:account, :aws_user_id => '1234'))
|
49
|
+
View.should_receive(:new).at_least(1).and_return(double(:view, :index => true))
|
50
|
+
Inform.should_receive(:info).at_least(1)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe :show do
|
55
|
+
context "AMI doesn't exist" do
|
56
|
+
it "should raise error" do
|
57
|
+
images.stub(:all => [])
|
58
|
+
lambda { controller.show(ami_name) }.should raise_error /not found/i
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "AMI exists" do
|
63
|
+
before { images.stub(:all => [ami]) }
|
64
|
+
after { controller.show(ami_name) }
|
65
|
+
|
66
|
+
it "should show the ami" do
|
67
|
+
View.should_receive(:new).and_return(double(:view, :show => true))
|
68
|
+
Inform.should_receive(:info)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe :show do
|
74
|
+
context "AMI doesn't exist" do
|
75
|
+
it "should raise error" do
|
76
|
+
images.stub(:all => [])
|
77
|
+
lambda { controller.show(ami_name) }.should raise_error /not found/i
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "AMI exists" do
|
82
|
+
before { images.stub(:all => [ami]) }
|
83
|
+
after { controller.show(ami_name) }
|
84
|
+
|
85
|
+
it "should show the ami" do
|
86
|
+
View.should_receive(:new).and_return(double(:view, :show => true))
|
87
|
+
Inform.should_receive(:info)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe :destroy do
|
93
|
+
context "AMI doesn't exist" do
|
94
|
+
it "should error if the ami doesn't exist" do
|
95
|
+
images.stub(:all => [])
|
96
|
+
lambda { controller.destroy(ami_name) }.should raise_error /not found/i
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "AMI exists" do
|
101
|
+
before do
|
102
|
+
controller.stub(:agree => true)
|
103
|
+
images.stub(:all => [ami])
|
104
|
+
end
|
105
|
+
|
106
|
+
after { controller.destroy(ami_name, options) }
|
107
|
+
|
108
|
+
context "with no options" do
|
109
|
+
let(:options) { {} }
|
110
|
+
|
111
|
+
it "should find an AMI and destroy it if agreement is given" do
|
112
|
+
images.should_receive(:all).with('name' => ami_name).and_return([ami])
|
113
|
+
ami.should_receive(:deregister)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should ask the user for confirmation before destroying the AMI" do
|
117
|
+
controller.should_receive(:agree).and_return(true)
|
118
|
+
ami.should_receive(:deregister)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not destroy the AMI if agreement is not given" do
|
122
|
+
controller.should_receive(:agree).and_return(false)
|
123
|
+
ami.should_not_receive(:deregister)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "with :force => true" do
|
128
|
+
let(:options) { { :force => true } }
|
129
|
+
|
130
|
+
it "should not ask for agreement" do
|
131
|
+
controller.should_not_receive(:agree)
|
132
|
+
ami.should_receive(:deregister)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe DeployController do
|
4
|
+
|
5
|
+
let (:type) { 'puge' }
|
6
|
+
let (:tag) { 'puge-1.16.1' }
|
7
|
+
let (:rails_env) { 'development' }
|
8
|
+
let (:environment_name) { 'myenvironment' }
|
9
|
+
let (:opts) { { 'tag' => tag, 'rails_env' => rails_env } }
|
10
|
+
|
11
|
+
describe :create do
|
12
|
+
before :each do
|
13
|
+
@servers = []
|
14
|
+
(0..1).each { @servers << double('Server').as_null_object }
|
15
|
+
@server = @servers.first
|
16
|
+
Server.stub(:find => [])
|
17
|
+
Database.stub(:get => nil)
|
18
|
+
@environment = double('Environment', :servers => @servers)
|
19
|
+
Environment.stub(:get => @environment)
|
20
|
+
end
|
21
|
+
|
22
|
+
context "no servers exist for the nominated environment" do
|
23
|
+
it "should not raise an error" do
|
24
|
+
environment = double('Environment', :servers => [])
|
25
|
+
Environment.stub(:get).and_return(environment)
|
26
|
+
lambda { DeployController.new.create(type, environment_name, { 'tag' => tag, 'rails_env' => rails_env }) }.should raise_error /instances already terminated/
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should create an instance of Deploy and deploy" do
|
31
|
+
deploy_run = double('Deploy::Run')
|
32
|
+
Deploy::Run.should_receive(:new).with(type, @environment, opts).and_return(deploy_run)
|
33
|
+
deploy_run.should_receive(:deploy)
|
34
|
+
DeployController.new.create(type, environment_name, opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe EnvironmentsController do
|
4
|
+
subject { EnvironmentsController.new }
|
5
|
+
|
6
|
+
after { subject }
|
7
|
+
|
8
|
+
describe :create do
|
9
|
+
let(:profile) { mock(:profile, :keypair => 'default') }
|
10
|
+
before {
|
11
|
+
@env = double(:environment)
|
12
|
+
Profile.should_receive(:read).with('profile_name').and_return(profile)
|
13
|
+
subject.stub(:agree => true)
|
14
|
+
}
|
15
|
+
|
16
|
+
after { subject.create(:name , 'profile_name', options) }
|
17
|
+
|
18
|
+
|
19
|
+
context "no options" do
|
20
|
+
let(:options) { {} }
|
21
|
+
|
22
|
+
it "should ask the user for confirmation before destroying the environment" do
|
23
|
+
Environment.should_receive(:create).with(:name, profile).and_return(@env)
|
24
|
+
@env.should_receive(:show)
|
25
|
+
subject.should_receive(:agree).and_return(true)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not create the environment if agreement is not given" do
|
29
|
+
subject.should_receive(:agree).and_return(false)
|
30
|
+
@env.should_not_receive(:create)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context ":force => true" do
|
35
|
+
let(:options) { {:force => true} }
|
36
|
+
|
37
|
+
it "should not ask for agreement" do
|
38
|
+
Environment.should_receive(:create).with(:name, profile).and_return(@env)
|
39
|
+
subject.should_not_receive(:agree)
|
40
|
+
@env.should_receive(:show)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe :index do
|
46
|
+
after { subject.index }
|
47
|
+
|
48
|
+
it "should index the environments" do
|
49
|
+
Environment.should_receive(:index)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe :show do
|
54
|
+
let(:name) { 'foo' }
|
55
|
+
|
56
|
+
before {
|
57
|
+
Environment.should_receive(:get).with(name).and_return(environment)
|
58
|
+
}
|
59
|
+
|
60
|
+
context "environment doesn't exist" do
|
61
|
+
let(:environment) { nil }
|
62
|
+
|
63
|
+
it "should raise an exception" do
|
64
|
+
lambda { subject.show('foo') }.should raise_error /not found/
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "environment exists" do
|
69
|
+
let(:environment) { double('Environment') }
|
70
|
+
|
71
|
+
after { subject.show(name) }
|
72
|
+
|
73
|
+
it "should show an environment" do
|
74
|
+
environment.should_receive(:show)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe :destroy do
|
81
|
+
let(:name) { 'foo' }
|
82
|
+
|
83
|
+
before {
|
84
|
+
Environment.should_receive(:get).with(name).and_return(environment)
|
85
|
+
}
|
86
|
+
|
87
|
+
context "environment doesn't exist" do
|
88
|
+
let(:environment) { nil }
|
89
|
+
|
90
|
+
it "should raise an exception" do
|
91
|
+
lambda { subject.destroy(name) }.should raise_error /not found/
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "environment exists" do
|
96
|
+
let(:environment) { double('Environment', :destroy => true, :show => true) }
|
97
|
+
|
98
|
+
before { subject.stub(:agree => true) }
|
99
|
+
|
100
|
+
after { subject.destroy(name, options) }
|
101
|
+
|
102
|
+
context "no options" do
|
103
|
+
let(:options) { {} }
|
104
|
+
|
105
|
+
it "should show the environment before destroying it" do
|
106
|
+
environment.should_receive(:show)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should find an environment and destroy it if agreement is given" do
|
110
|
+
environment.should_receive(:destroy)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should ask the user for confirmation before destroying the environment" do
|
114
|
+
subject.should_receive(:agree).and_return(true)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should not destroy the environment if agreement is not given" do
|
118
|
+
subject.should_receive(:agree).and_return(false)
|
119
|
+
environment.should_not_receive(:destroy)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context ":force => true" do
|
124
|
+
let(:options) { {:force => true} }
|
125
|
+
|
126
|
+
it "should not ask for agreement" do
|
127
|
+
subject.should_not_receive(:agree)
|
128
|
+
environment.should_receive(:destroy)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|