stackster 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,5 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  .rvmrc
6
+ coverage
7
+ *.swp
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ ## v0.3.0
2
+
3
+ * Now uses consistent reads
4
+ * Increased the testing coverage
5
+
1
6
  ## v0.2.9
2
7
 
3
8
  * Bug fix in private method.
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Run specs'
5
+
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.rspec_opts = %w(--color)
8
+ end
@@ -28,7 +28,7 @@ module Stackster
28
28
  end
29
29
 
30
30
  def select(query)
31
- @connect.select(query).body['Items']
31
+ @connect.select(query, 'ConsistentRead' => true).body['Items']
32
32
  end
33
33
 
34
34
  def delete(domain, key)
@@ -24,7 +24,7 @@ module Stackster
24
24
  end
25
25
 
26
26
  def save
27
- set_name_attribute
27
+ set_default_attributes
28
28
 
29
29
  attributes.each_pair do |key,value|
30
30
  @logger.debug "Setting attribute #{key}=#{value}"
@@ -45,8 +45,9 @@ module Stackster
45
45
 
46
46
  private
47
47
 
48
- def set_name_attribute
48
+ def set_default_attributes
49
49
  attributes.merge!('Name' => name)
50
+ attributes.merge!('CreatedAt' => Time.now.utc)
50
51
  end
51
52
 
52
53
  def get_attributes
@@ -5,9 +5,6 @@ module Stackster
5
5
  @config = args[:config]
6
6
  end
7
7
 
8
- # Data structure is return deffernelty for class
9
- # ToDo - Add support for classic
10
- # Currently only supports VPC
11
8
  def list_stack_instances(stack_name)
12
9
  h = []
13
10
  describe_instances.each do |instance|
@@ -50,10 +50,6 @@ module Stackster
50
50
  stack_reader.attributes
51
51
  end
52
52
 
53
- def show
54
- stack_reader.show
55
- end
56
-
57
53
  def outputs
58
54
  stack_reader.outputs
59
55
  end
@@ -1,3 +1,3 @@
1
1
  module Stackster
2
- VERSION = "0.2.9"
2
+ VERSION = "0.3.0"
3
3
  end
data/script/ci_setup CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  # Source RVM profile and set ruby / gemset
4
4
  . /etc/profile
5
- rvm use "1.9.3-p125@stackster" --create
5
+
6
+ # Exit with error if any command returns non zero
7
+ set -e
6
8
 
7
9
  # Bundle gems
10
+ rvm use "1.9.3-p125@stackster" --create
8
11
  bundle
9
12
 
10
- # Create blank deployment config
11
- touch $HOME/.stackster.yml
12
-
13
13
  # Run spec tests
14
- rspec spec
14
+ rake spec
@@ -1,9 +1,39 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Stackster do
4
+ before do
5
+ #@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
6
+ @logger_mock = mock 'Logger'
7
+ @config_stub = stub 'Config', :logger => @logger_mock, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
4
8
 
5
- ['error'].each do |t|
6
- it "should test #{t}"
9
+ @exception_stub1 = stub 'Excon::Response'
10
+ @exception_stub1.stub(:response).and_return(@exception_stub1)
11
+ @exception_stub1.stub(:body).and_return('<opt><Error><Message>No updates are to be performed.</Message></Error></opt>')
12
+
13
+ @exception_stub2 = stub 'Excon::Response'
14
+ @exception_stub2.stub(:response).and_return(@exception_stub2)
15
+ @exception_stub2.stub(:body).and_return('<opt><Error><Message>Oops.</Message></Error></opt>')
7
16
  end
8
17
 
18
+ describe 'process' do
19
+ it 'should process no update messages' do
20
+ @logger_mock.should_receive(:info).with('No updates are to be performed.')
21
+
22
+ error = Stackster::AWS::CloudFormation::Error.new :exception => @exception_stub1, :config => @config_stub
23
+ error.process
24
+ end
25
+
26
+ it 'should process general messages' do
27
+ @logger_mock.should_receive(:error).with('Oops.')
28
+
29
+ error = Stackster::AWS::CloudFormation::Error.new :exception => @exception_stub2, :config => @config_stub
30
+
31
+ begin
32
+ error.process
33
+ fail 'should have exited'
34
+ rescue SystemExit => e
35
+ e.status.should == 1
36
+ end
37
+ end
38
+ end
9
39
  end
@@ -1,10 +1,174 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Stackster do
4
+ before do
5
+ @logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
6
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
7
+ @error_stub = stub 'Error', :process => 'Processed Error'
8
+ @response_stub = stub 'Excon::Response', :body => {
9
+ 'Stacks' => [{'StackStatus' => 'green', 'Outputs' => [{'key' => 'value'}]}],
10
+ 'StackResources' => [{'StackName' => 'my_stack'}],
11
+ 'StackEvents' => ['event1', 'event2'],
12
+ 'TemplateBody' => '{EIP: "string"}'
13
+ }
4
14
 
5
- ['create', 'update', 'destroy', 'describe_stack', 'stack_resources',
6
- 'stack_events', 'stack_status', 'stack_outputs', 'template'].each do |t|
7
- it "should test #{t}"
15
+ @cf_mock = mock 'CloudFormation'
16
+ Fog::AWS::CloudFormation.stub(:new).and_return(@cf_mock)
17
+
18
+ @args = {
19
+ :parameters => { 'parameter1' => 'my_param' },
20
+ :name => 'my_stack',
21
+ :template => 'my_template'
22
+ }
23
+
24
+ @exception = Exception.new('Failed')
25
+
26
+ @cf = Stackster::AWS::CloudFormation.new(:config => @config_stub)
27
+ end
28
+
29
+ describe "create" do
30
+ it "should create the stack on Cloud Formation" do
31
+ @cf_mock.should_receive(:create_stack).with('my_stack',
32
+ { 'Capabilities' => ['CAPABILITY_IAM'],
33
+ 'TemplateBody' => 'my_template',
34
+ 'Parameters' => { 'parameter1' => 'my_param' }
35
+ })
36
+
37
+ @cf.create(@args)
38
+ end
39
+
40
+ it "should trap exceptions" do
41
+ @cf_mock.should_receive(:create_stack).with('my_stack',
42
+ { 'Capabilities' => ['CAPABILITY_IAM'],
43
+ 'TemplateBody' => 'my_template',
44
+ 'Parameters' => { 'parameter1' => 'my_param' }
45
+ }).and_raise(@exception)
46
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
47
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
48
+
49
+ @cf.create(@args).should == 'Processed Error'
50
+ end
8
51
  end
9
52
 
53
+ describe "update" do
54
+ it "should update the stack on Cloud Formation" do
55
+ @cf_mock.should_receive(:update_stack).with('my_stack',
56
+ { 'Capabilities' => ['CAPABILITY_IAM'],
57
+ 'TemplateBody' => 'my_template',
58
+ 'Parameters' => { 'parameter1' => 'my_param' }
59
+ })
60
+
61
+ @cf.update(@args)
62
+ end
63
+
64
+ it "should trap exceptions" do
65
+ @cf_mock.should_receive(:update_stack).with('my_stack',
66
+ { 'Capabilities' => ['CAPABILITY_IAM'],
67
+ 'TemplateBody' => 'my_template',
68
+ 'Parameters' => { 'parameter1' => 'my_param' }
69
+ }).and_raise(@exception)
70
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
71
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
72
+
73
+ @cf.update(@args).should == 'Processed Error'
74
+ end
75
+ end
76
+
77
+
78
+ describe 'destroy' do
79
+ it "should delete the stack on Cloud Formation" do
80
+ @cf_mock.should_receive(:delete_stack).with('my_stack')
81
+
82
+ @cf.destroy('my_stack')
83
+ end
84
+
85
+ it "should trap exceptions" do
86
+ @cf_mock.should_receive(:delete_stack).with('my_stack').and_raise(@exception)
87
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
88
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
89
+
90
+ @cf.destroy('my_stack').should == 'Processed Error'
91
+ end
92
+ end
93
+
94
+
95
+ describe 'describe_stack' do
96
+ it "should return the Cloud Formation description of the stack" do
97
+ @cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_return(@response_stub)
98
+
99
+ @cf.describe_stack('my_stack').should == [{'StackStatus' => 'green', 'Outputs' => [{'key' => 'value'}]}]
100
+ end
101
+
102
+ it "should trap exceptions" do
103
+ @cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_raise(@exception)
104
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
105
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
106
+
107
+ @cf.describe_stack('my_stack').should == 'Processed Error'
108
+ end
109
+ end
110
+
111
+ describe "stack_resources" do
112
+ it "should return the Cloud Formation description of the stack resources" do
113
+ @cf_mock.should_receive(:describe_stack_resources).with('StackName' => 'my_stack').and_return(@response_stub)
114
+
115
+ @cf.stack_resources('my_stack').should == [{'StackName' => 'my_stack'}]
116
+ end
117
+
118
+ it "should trap exceptions" do
119
+ @cf_mock.should_receive(:describe_stack_resources).with('StackName' => 'my_stack').and_raise(@exception)
120
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
121
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
122
+
123
+ @cf.stack_resources('my_stack').should == 'Processed Error'
124
+ end
125
+ end
126
+
127
+ describe "stack_events" do
128
+ it "should return the Cloud Formation description of the stack events" do
129
+ @cf_mock.should_receive(:describe_stack_events).with('my_stack').and_return(@response_stub)
130
+
131
+ @cf.stack_events('my_stack', 2).should == ['event1', 'event2']
132
+ end
133
+
134
+ it "should trap exceptions" do
135
+ @cf_mock.should_receive(:describe_stack_events).with('my_stack').and_raise(@exception)
136
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
137
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
138
+
139
+ @cf.stack_events('my_stack', 2).should == 'Processed Error'
140
+ end
141
+ end
142
+
143
+ describe "stack_status" do
144
+ it "should return the Cloud Formation status of the stack" do
145
+ @cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_return(@response_stub)
146
+
147
+ @cf.stack_status('my_stack').should == 'green'
148
+ end
149
+ end
150
+
151
+ describe "stack_outputs" do
152
+ it "should return the Cloud Formation outputs for the stack" do
153
+ @cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_return(@response_stub)
154
+
155
+ @cf.stack_outputs('my_stack').should == [{'key' => 'value'}]
156
+ end
157
+ end
158
+
159
+ describe "template" do
160
+ it "should return the Cloud Formation template for the stack" do
161
+ @cf_mock.should_receive(:get_template).with('my_stack').and_return(@response_stub)
162
+
163
+ @cf.template('my_stack').should == '{EIP: "string"}'
164
+ end
165
+
166
+ it "should trap exceptions" do
167
+ @cf_mock.should_receive(:get_template).with('my_stack').and_raise(@exception)
168
+ Stackster::AWS::CloudFormation::Error.should_receive(:new).
169
+ with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
170
+
171
+ @cf.template('my_stack').should == 'Processed Error'
172
+ end
173
+ end
10
174
  end
data/spec/aws/ec2_spec.rb CHANGED
@@ -1,7 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Stackster do
4
+ before do
5
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
6
+ @response_stub = stub 'Excon::Response', :body => {
7
+ 'reservationSet' => [{'instanceSet' => [{'ipAddress' => '192.168.1.1'}]}]
8
+ }
4
9
 
5
- it "should test describe instances"
10
+ @cf_mock = mock 'CloudFormation'
11
+ Fog::Compute::AWS.stub(:new).and_return(@cf_mock)
6
12
 
13
+ @ec2 = Stackster::AWS::EC2.new(:config => @config_stub)
14
+ end
15
+
16
+ describe "describe_instances" do
17
+ it "should return the Cloud Formation description of the instances" do
18
+ @cf_mock.should_receive(:describe_instances).and_return(@response_stub)
19
+
20
+ @ec2.describe_instances.should == [{'instanceSet' => [{'ipAddress' => '192.168.1.1'}]}]
21
+ end
22
+ end
7
23
  end
@@ -1,10 +1,72 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Stackster do
4
+ before do
5
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
6
+ @response_stub = stub 'Excon::Response', :body => {
7
+ 'RequestId' => 'rid',
8
+ 'Domains' => ['domain1', 'domain2'],
9
+ 'Items' => { 'item1' => { 'key' => ['value'] } }
10
+ }
4
11
 
5
- ['domains', 'create_domain', 'put_attributes',
6
- 'select', 'delete' ].each do |t|
7
- it "should test #{t}"
12
+ @db_mock = mock 'SimpleDB'
13
+ Fog::AWS::SimpleDB.stub(:new).and_return(@db_mock)
14
+ @db_mock.stub(:list_domains).and_return(@response_stub)
15
+
16
+ @db = Stackster::AWS::SimpleDB.new(:config => @config_stub)
17
+ end
18
+
19
+ describe 'domains' do
20
+ it 'should return a list of domains' do
21
+ @db.domains.should == ['domain1', 'domain2']
22
+ end
23
+ end
24
+
25
+ describe 'domain_exists?' do
26
+ it 'should return true for existing domains' do
27
+ @db.domain_exists?('domain1').should be_true
28
+ end
29
+
30
+ it 'should return false for non-existent domains' do
31
+ @db.domain_exists?('baddomain1').should_not be_true
32
+ end
8
33
  end
9
34
 
35
+ describe 'create_domain' do
36
+ it 'should create a new domain' do
37
+ @db_mock.should_receive(:create_domain).with('newdomain').and_return(@response_stub)
38
+
39
+ @db.create_domain('newdomain').body['RequestId'].should == 'rid'
40
+ end
41
+
42
+ it 'should not create a duplicate domain' do
43
+ @db_mock.should_not_receive(:create_domain)
44
+
45
+ @db.create_domain('domain1').should be_nil
46
+ end
47
+ end
48
+
49
+ describe 'put_attributes' do
50
+ it 'should update the specified domain' do
51
+ @db_mock.should_receive(:put_attributes).with('domain1', 'item1', { 'key' => 'value' }, {}).and_return(@response_stub)
52
+
53
+ @db.put_attributes('domain1', 'item1', { 'key' => 'value' }, {}).body['RequestId'].should == 'rid'
54
+ end
55
+ end
56
+
57
+ describe 'select' do
58
+ it 'should return query items' do
59
+ @db_mock.should_receive(:select).with('item1', { "ConsistentRead" => true } ).and_return(@response_stub)
60
+
61
+ @db.select('item1').should == { 'item1' => { 'key' => ['value'] } }
62
+ end
63
+ end
64
+
65
+ describe 'delete' do
66
+ it 'should delete the attributes identified by domain and key' do
67
+ @db_mock.should_receive(:delete_attributes).with('domain1', 'item1').and_return(@response_stub)
68
+
69
+ @db.delete('domain1', 'item1').body['RequestId'].should == 'rid'
70
+ end
71
+ end
10
72
  end
data/spec/entry_spec.rb CHANGED
@@ -57,14 +57,12 @@ describe Stackster do
57
57
  @entry.name.should == 'test-stack-us-west-1'
58
58
  end
59
59
 
60
- it "should set the Name attribute to stack name before saving"
61
-
62
- it "should set the attributes in simple db" do
60
+ it "should set the attributes in simple db including default attributes" do
63
61
  @simple_db_mock.should_receive(:put_attributes).
64
62
  with("stacks",
65
63
  "test-stack-us-west-1",
66
- { "key" => "value", "Name" => "test-stack-us-west-1" },
67
- { :replace => ["key", "Name"] } )
64
+ { "key" => "value", "Name" => "test-stack-us-west-1", "CreatedAt" => anything },
65
+ { :replace => ["key", "Name", "CreatedAt"] } )
68
66
  @entry.attributes = {"key"=>"value"}
69
67
 
70
68
  @entry.save
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
3
 
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_filter "/spec/"
7
+ end
8
+
4
9
  require 'stackster'
5
10
 
6
11
  RSpec.configure do |config|
@@ -1,10 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Stackster do
4
+ before do
5
+ @logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
6
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
4
7
 
5
- ['attributes', 'attribute_names', 'instances_private_ip_addresses',
6
- 'display', 'resources', 'template'].each do |t|
7
- it "should test #{t}"
8
+ @stack_reader_mock = mock 'StackReader'
9
+ Stackster::StackReader.stub(:new).and_return(@stack_reader_mock)
10
+ @stack_reader_mock.stub(:attributes).and_return(:chef_repo_bucket_prefix => 'chef_repo_bp')
11
+ @stack_reader_mock.stub(:outputs).and_return([{'key' => 'value'}])
12
+ @stack_reader_mock.stub(:status).and_return('green')
13
+ @stack_reader_mock.stub(:events).and_return(['event1', 'event2', 'event3'])
14
+ @stack_reader_mock.stub(:resources).and_return([{'StackName' => 'my_stack'}])
15
+
16
+ @stack_formater = Stackster::StackFormater.new(:name => 'my_stack', :config => @config_stub)
8
17
  end
9
18
 
19
+ describe 'display' do
20
+ it 'should return formatted information for the stack' do
21
+ @stack_formater.display.should == {
22
+ 'attributes' => { :chef_repo_bucket_prefix => 'chef_repo_bp' },
23
+ 'status' => 'green',
24
+ 'outputs' => [{'key' => 'value'}],
25
+ 'events' => ['event1', 'event2', 'event3'],
26
+ 'resources' => [{'StackName' => 'my_stack'}]
27
+ }
28
+ end
29
+ end
10
30
  end
@@ -1,10 +1,75 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Stackster do
4
+ before do
5
+ @logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
6
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
4
7
 
5
- ['attributes', 'outputs', 'status', 'events', 'resources',
6
- 'instances', 'resources', 'template'].each do |t|
7
- it "should test #{t}"
8
+ @entry_mock = mock 'Entry'
9
+ @entry_mock.stub(:attributes).and_return(:chef_repo_bucket_prefix => 'chef_repo_bp')
10
+ Stackster::Entry.stub(:new).and_return(@entry_mock)
11
+
12
+ @cf_mock = mock 'CloudFormation'
13
+ Stackster::AWS::CloudFormation.stub(:new).and_return(@cf_mock)
14
+ @cf_mock.stub(:stack_outputs).and_return([{'key' => 'value'}])
15
+ @cf_mock.stub(:stack_status).and_return('green')
16
+ @cf_mock.stub(:stack_events).and_return(['event1', 'event2'])
17
+ @cf_mock.stub(:stack_resources).and_return([{'StackName' => 'my_stack'}])
18
+ @cf_mock.stub(:template).and_return('{"Parameters": {"EIP": "string"}}')
19
+
20
+ @instance_reader_mock = mock 'InstanceReader'
21
+ Stackster::InstanceReader.stub(:new).and_return(@instance_reader_mock)
22
+ @instance_reader_mock.stub(:list_stack_instances).and_return(['instance1', 'instance2'])
23
+
24
+ @stack_reader = Stackster::StackReader.new(:name => 'my_stack', :config => @config_stub)
25
+ end
26
+
27
+
28
+ describe 'attributes' do
29
+ it 'should return the stack attributes' do
30
+ @stack_reader.attributes.should == { :chef_repo_bucket_prefix => 'chef_repo_bp' }
31
+ end
32
+ end
33
+
34
+ describe 'outputs' do
35
+ it 'should return the stack outputs' do
36
+ @stack_reader.outputs.should == [{'key' => 'value'}]
37
+ end
38
+ end
39
+
40
+ describe 'status' do
41
+ it 'should return the stack status' do
42
+ @stack_reader.status.should == 'green'
43
+ end
8
44
  end
9
45
 
46
+ describe 'events' do
47
+ it 'should return the stack events' do
48
+ @stack_reader.events(2).should == ['event1', 'event2']
49
+ end
50
+ end
51
+
52
+ describe 'resources' do
53
+ it 'should return the stack resources' do
54
+ @stack_reader.resources.should == [{'StackName' => 'my_stack'}]
55
+ end
56
+ end
57
+
58
+ describe 'template' do
59
+ it 'should return the stack template' do
60
+ @stack_reader.template.should == '{"Parameters": {"EIP": "string"}}'
61
+ end
62
+ end
63
+
64
+ describe 'parameters' do
65
+ it 'should return the stack parameters' do
66
+ @stack_reader.parameters.should == ['EIP']
67
+ end
68
+ end
69
+
70
+ describe 'instances' do
71
+ it 'should return the stack instances' do
72
+ @stack_reader.instances.should == ['instance1', 'instance2']
73
+ end
74
+ end
10
75
  end
data/spec/stack_spec.rb CHANGED
@@ -26,11 +26,12 @@ describe Stackster do
26
26
 
27
27
  describe "mocking a stack object" do
28
28
  before do
29
- @config_mock = mock 'config mock'
30
- Stackster::Config.should_receive(:new).and_return @config_mock
29
+ @logger_stub = stub 'logger stub', :info => 'true', :warn => 'true', :error => 'true'
30
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west-1'
31
+ Stackster::Config.should_receive(:new).and_return @config_stub
31
32
  @entry_mock = mock 'entry mock'
32
33
  Stackster::Entry.should_receive(:new).with(:name => 'test-stack',
33
- :config => @config_mock).
34
+ :config => @config_stub).
34
35
  and_return @entry_mock
35
36
  @stack = Stackster::Stack.new :name => 'test-stack',
36
37
  :config => 'my-config',
@@ -38,7 +39,6 @@ describe Stackster do
38
39
  end
39
40
 
40
41
  context "when creating a stack" do
41
-
42
42
  it "should create a new stack" do
43
43
  stack_creater_mock = mock 'stack creater'
44
44
  @entry_mock.should_receive(:set_attributes).
@@ -48,7 +48,7 @@ describe Stackster do
48
48
  with(:name => 'test-stack',
49
49
  :entry => @entry_mock,
50
50
  :template_file => 'template_file',
51
- :config => @config_mock).
51
+ :config => @config_stub).
52
52
  and_return stack_creater_mock
53
53
  stack_creater_mock.should_receive(:create)
54
54
 
@@ -56,13 +56,22 @@ describe Stackster do
56
56
  :attributes => { 'test-attr' => 'test-value' }
57
57
  end
58
58
 
59
- it "should not create a stack entry if the create fails"
60
-
59
+ it "should not create a stack entry if the create fails" do
60
+ @entry_mock.should_receive(:set_attributes).
61
+ with({ 'test-attr' => 'test-value' })
62
+ @entry_mock.should_not_receive(:save)
63
+
64
+ begin
65
+ @stack.create :template => 'template_file',
66
+ :attributes => { 'test-attr' => 'test-value' }
67
+ fail "should have raised Errno::ENOENT"
68
+ rescue Errno::ENOENT
69
+ end
70
+ end
61
71
  end
62
72
 
63
73
  context "when updating a stack" do
64
-
65
- it "should should update an existing stack" do
74
+ it "should update an existing stack" do
66
75
  stack_updater_mock = mock 'stack updater'
67
76
  stack_reader_mock = mock 'stack reader'
68
77
  @entry_mock.should_receive(:set_attributes).
@@ -72,20 +81,47 @@ describe Stackster do
72
81
 
73
82
  Stackster::StackReader.should_receive(:new).
74
83
  with(:name => 'test-stack',
75
- :config => @config_mock).
84
+ :config => @config_stub).
76
85
  and_return stack_reader_mock
77
86
  Stackster::StackUpdater.should_receive(:new).
78
87
  with(:name => 'test-stack',
79
88
  :entry => @entry_mock,
80
89
  :template_body => 'template-body-json',
81
- :config => @config_mock).
90
+ :config => @config_stub).
82
91
  and_return stack_updater_mock
83
92
  stack_updater_mock.should_receive(:update_stack_if_parameters_changed).
84
93
  and_return true
85
94
  @stack.update :attributes => { 'update' => 'test-attrs' }
86
95
  end
87
96
 
88
- it "should not update a stack entry if the create fails"
97
+ it "should not update a stack entry if the update fails" do
98
+ @entry_mock.should_receive(:set_attributes).
99
+ with({ 'update' => 'test-attrs' })
100
+ @entry_mock.should_not_receive(:save)
101
+
102
+ stack_reader_mock = mock 'stack reader'
103
+ stack_reader_mock.should_receive(:template).and_return('template-body-json')
104
+ Stackster::StackReader.should_receive(:new).
105
+ with(:name => 'test-stack',
106
+ :config => @config_stub).
107
+ and_return stack_reader_mock
108
+
109
+ stack_updater_mock = mock 'stack updater'
110
+ Stackster::StackUpdater.should_receive(:new).
111
+ with(:name => 'test-stack',
112
+ :entry => @entry_mock,
113
+ :template_body => 'template-body-json',
114
+ :config => @config_stub).
115
+ and_return stack_updater_mock
116
+ stack_updater_mock.should_receive(:update_stack_if_parameters_changed).
117
+ and_raise('test-stack has not reached a stable state')
118
+
119
+ begin
120
+ @stack.update :attributes => { 'update' => 'test-attrs' }
121
+ fail 'should have raised RuntimeException'
122
+ rescue RuntimeError
123
+ end
124
+ end
89
125
  end
90
126
 
91
127
  context "when destroying a stack" do
@@ -93,20 +129,97 @@ describe Stackster do
93
129
  stack_destroyer_mock = mock 'stack destroyer'
94
130
  Stackster::StackDestroyer.should_receive(:new).
95
131
  with(:name => 'test-stack',
96
- :config => @config_mock).
132
+ :config => @config_stub).
97
133
  and_return stack_destroyer_mock
98
134
  stack_destroyer_mock.should_receive(:destroy)
99
135
  @entry_mock.should_receive(:delete_attributes)
100
136
  @stack.destroy
101
137
  end
102
138
  end
139
+ end
140
+
141
+ describe 'wrapper methods' do
142
+ before do
143
+ @logger_stub = stub 'logger stub', :info => 'true', :warn => 'true', :error => 'true'
144
+ @config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west-1'
145
+ @entry_stub = stub 'Entry'
146
+ Stackster::Config.should_receive(:new).and_return(@config_stub)
147
+ Stackster::Entry.should_receive(:new).and_return(@entry_stub)
148
+
149
+ @stack = Stackster::Stack.new :name => 'test-stack',
150
+ :config => @config_stub,
151
+ :logger => @logger_stub
152
+ end
103
153
 
104
- ['attributes', 'display', 'show', 'outputs',
105
- 'status', 'events', 'instances', 'instances_public_ip_addresses',
106
- 'instances_private_ip_addresses', 'resources', 'template'].each do |t|
107
- it "should test #{t}"
154
+ context "formater" do
155
+ before do
156
+ @stack_formater_mock = mock 'StackFormater'
157
+ Stackster::StackFormater.should_receive(:new).and_return(@stack_formater_mock)
158
+ @stack_formater_mock.stub(:display).and_return({
159
+ 'attributes' => { :chef_repo_bucket_prefix => 'chef_repo_bp' },
160
+ 'status' => 'green',
161
+ 'outputs' => [{'key' => 'value'}],
162
+ 'events' => ['event1', 'event2', 'event3'],
163
+ 'resources' => [{'StackName' => 'test-stack'}]
164
+ })
165
+ end
166
+
167
+ it 'should display formatted stack attributes' do
168
+ @stack.display.should == {
169
+ 'attributes' => { :chef_repo_bucket_prefix => 'chef_repo_bp' },
170
+ 'status' => 'green',
171
+ 'outputs' => [{'key' => 'value'}],
172
+ 'events' => ['event1', 'event2', 'event3'],
173
+ 'resources' => [{'StackName' => 'test-stack'}]
174
+ }
175
+ end
108
176
  end
109
177
 
110
- end
178
+ context 'reader' do
179
+ before do
180
+ @stack_reader_mock = mock 'StackReader'
181
+ Stackster::StackReader.should_receive(:new).and_return(@stack_reader_mock)
182
+ @stack_reader_mock.stub(:attributes).and_return(:chef_repo_bucket_prefix => 'chef_repo_bp')
183
+ @stack_reader_mock.stub(:outputs).and_return([{'key' => 'value'}])
184
+ @stack_reader_mock.stub(:status).and_return('green')
185
+ @stack_reader_mock.stub(:events).and_return(['event1', 'event2', 'event3'])
186
+ @stack_reader_mock.stub(:resources).and_return([{'StackName' => 'my_stack'}])
187
+ @stack_reader_mock.stub(:template).and_return('{"Parameters": {"EIP": "string"}}')
188
+ @stack_reader_mock.stub(:parameters).and_return(['EIP'])
189
+ @stack_reader_mock.stub(:instances).and_return(['instance1', 'instance2'])
190
+ end
191
+
192
+ it 'should return the stack attributes' do
193
+ @stack.attributes.should == { :chef_repo_bucket_prefix => 'chef_repo_bp' }
194
+ end
195
+
196
+ it 'should return the stack outputs' do
197
+ @stack.outputs.should == [{'key' => 'value'}]
198
+ end
111
199
 
200
+ it 'should return the stack status' do
201
+ @stack.status.should == 'green'
202
+ end
203
+
204
+ it 'should return the stack events' do
205
+ @stack.events(3).should == ['event1', 'event2', 'event3']
206
+ end
207
+
208
+ it 'should return the stack resources' do
209
+ @stack.resources.should == [{'StackName' => 'my_stack'}]
210
+ end
211
+
212
+ it 'should return the stack template' do
213
+ @stack.template.should == '{"Parameters": {"EIP": "string"}}'
214
+ end
215
+
216
+ it 'should return the stack parameters' do
217
+ @stack.parameters.should == ['EIP']
218
+ end
219
+
220
+ it 'should return the stack instances' do
221
+ @stack.instances.should == ['instance1', 'instance2']
222
+ end
223
+ end
224
+ end
112
225
  end
data/stackster.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  # specify any dependencies here; for example:
22
22
  s.add_development_dependency "rspec"
23
+ s.add_development_dependency "simplecov"
23
24
 
24
25
  s.add_runtime_dependency "fog"
25
26
  s.add_runtime_dependency 'logger'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-23 00:00:00.000000000 Z
12
+ date: 2012-10-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70160791318120 !ruby/object:Gem::Requirement
16
+ requirement: &2160251380 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,21 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70160791318120
24
+ version_requirements: *2160251380
25
+ - !ruby/object:Gem::Dependency
26
+ name: simplecov
27
+ requirement: &2160250100 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2160250100
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: fog
27
- requirement: &70160791317340 !ruby/object:Gem::Requirement
38
+ requirement: &2160248940 !ruby/object:Gem::Requirement
28
39
  none: false
29
40
  requirements:
30
41
  - - ! '>='
@@ -32,10 +43,10 @@ dependencies:
32
43
  version: '0'
33
44
  type: :runtime
34
45
  prerelease: false
35
- version_requirements: *70160791317340
46
+ version_requirements: *2160248940
36
47
  - !ruby/object:Gem::Dependency
37
48
  name: logger
38
- requirement: &70160791315460 !ruby/object:Gem::Requirement
49
+ requirement: &2160247880 !ruby/object:Gem::Requirement
39
50
  none: false
40
51
  requirements:
41
52
  - - ! '>='
@@ -43,10 +54,10 @@ dependencies:
43
54
  version: '0'
44
55
  type: :runtime
45
56
  prerelease: false
46
- version_requirements: *70160791315460
57
+ version_requirements: *2160247880
47
58
  - !ruby/object:Gem::Dependency
48
59
  name: trollop
49
- requirement: &70160791312720 !ruby/object:Gem::Requirement
60
+ requirement: &2160246820 !ruby/object:Gem::Requirement
50
61
  none: false
51
62
  requirements:
52
63
  - - ! '>='
@@ -54,10 +65,10 @@ dependencies:
54
65
  version: '0'
55
66
  type: :runtime
56
67
  prerelease: false
57
- version_requirements: *70160791312720
68
+ version_requirements: *2160246820
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: xml-simple
60
- requirement: &70160791309680 !ruby/object:Gem::Requirement
71
+ requirement: &2160244280 !ruby/object:Gem::Requirement
61
72
  none: false
62
73
  requirements:
63
74
  - - ! '>='
@@ -65,7 +76,7 @@ dependencies:
65
76
  version: '0'
66
77
  type: :runtime
67
78
  prerelease: false
68
- version_requirements: *70160791309680
79
+ version_requirements: *2160244280
69
80
  description: Thats what I do
70
81
  email:
71
82
  - brett@weav.net
@@ -135,21 +146,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
146
  - - ! '>='
136
147
  - !ruby/object:Gem::Version
137
148
  version: '0'
138
- segments:
139
- - 0
140
- hash: 107402892190402761
141
149
  required_rubygems_version: !ruby/object:Gem::Requirement
142
150
  none: false
143
151
  requirements:
144
152
  - - ! '>='
145
153
  - !ruby/object:Gem::Version
146
154
  version: '0'
147
- segments:
148
- - 0
149
- hash: 107402892190402761
150
155
  requirements: []
151
156
  rubyforge_project: stackster
152
- rubygems_version: 1.8.16
157
+ rubygems_version: 1.8.10
153
158
  signing_key:
154
159
  specification_version: 3
155
160
  summary: I make deployments easier