dew 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|