ridley 0.7.0.rc1 → 0.7.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
@@ -47,7 +47,7 @@ module Ridley
47
47
  end
48
48
 
49
49
  new_attributes = client.connection.post("#{data_bag.class.resource_path}/#{data_bag.name}", resource.to_json).body
50
- resource.from_hash(resource.attributes.deep_merge(new_attributes))
50
+ resource.mass_assign(new_attributes)
51
51
  resource
52
52
  end
53
53
 
@@ -98,6 +98,9 @@ module Ridley
98
98
  type: String,
99
99
  required: true
100
100
 
101
+ alias_method :attributes=, :mass_assign
102
+ alias_method :attributes, :_attributes_
103
+
101
104
  # @param [Ridley::Client] client
102
105
  # @param [Ridley::DataBagResource] data_bag
103
106
  # @param [#to_hash] new_attrs
@@ -124,7 +127,7 @@ module Ridley
124
127
  def save
125
128
  raise Errors::InvalidResource.new(self.errors) unless valid?
126
129
 
127
- mass_assign(self.class.create(client, data_bag, self).attributes)
130
+ mass_assign(self.class.create(client, data_bag, self)._attributes_)
128
131
  true
129
132
  rescue Errors::HTTPConflict
130
133
  self.update
@@ -135,7 +138,7 @@ module Ridley
135
138
  #
136
139
  # @return [Hash] decrypted attributes
137
140
  def decrypt
138
- decrypted_hash = Hash[attributes.map { |key, value| [key, key == "id" ? value : decrypt_value(value)] }]
141
+ decrypted_hash = Hash[_attributes_.map { |key, value| [key, key == "id" ? value : decrypt_value(value)] }]
139
142
  mass_assign(decrypted_hash)
140
143
  end
141
144
 
@@ -154,7 +157,7 @@ module Ridley
154
157
  #
155
158
  # @return [Object]
156
159
  def reload
157
- mass_assign(self.class.find(client, data_bag, self).attributes)
160
+ mass_assign(self.class.find(client, data_bag, self)._attributes_)
158
161
  self
159
162
  end
160
163
 
@@ -168,7 +171,7 @@ module Ridley
168
171
  def update
169
172
  raise Errors::InvalidResource.new(self.errors) unless valid?
170
173
 
171
- mass_assign(sself.class.update(client, data_bag, self).attributes)
174
+ mass_assign(sself.class.update(client, data_bag, self)._attributes_)
172
175
  true
173
176
  end
174
177
 
@@ -176,14 +179,10 @@ module Ridley
176
179
  #
177
180
  # @return [Object]
178
181
  def from_hash(hash)
179
- hash = HashWithIndifferentAccess.new(hash.to_hash)
182
+ hash = Hashie::Mash.new(hash.to_hash)
180
183
 
181
184
  mass_assign(hash.has_key?(:raw_data) ? hash[:raw_data] : hash)
182
185
  self
183
186
  end
184
-
185
- def to_s
186
- self.attributes
187
- end
188
187
  end
189
188
  end
@@ -26,7 +26,7 @@ module Ridley
26
26
  #
27
27
  # @return [nil, Ridley::DataBagItemResource]
28
28
  def find!(client, data_bag, object)
29
- data_bag_item = DataBagItem.find!(client, data_bag, object)
29
+ data_bag_item = DataBagItemResource.find!(client, data_bag, object)
30
30
  data_bag_item.decrypt
31
31
  new(client, data_bag, data_bag_item.attributes)
32
32
  end
@@ -109,7 +109,7 @@ module Ridley
109
109
  upload_path = url.path
110
110
  url.path = ""
111
111
 
112
- Faraday.new(url) do |c|
112
+ Faraday.new(url, client.options.slice(*Connection::VALID_OPTIONS)) do |c|
113
113
  c.request :chef_auth, client.client_name, client.client_key
114
114
  c.adapter :net_http
115
115
  end.put(upload_path, contents, headers)
@@ -1,3 +1,3 @@
1
1
  module Ridley
2
- VERSION = "0.7.0.rc1"
2
+ VERSION = "0.7.0.rc3"
3
3
  end
@@ -19,12 +19,13 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_runtime_dependency 'json', '>= 1.5.0'
21
21
  s.add_runtime_dependency 'multi_json', '>= 1.0.4'
22
- s.add_runtime_dependency 'chozo', '>= 0.4.1'
23
- s.add_runtime_dependency 'mixlib-log'
24
- s.add_runtime_dependency 'mixlib-authentication'
22
+ s.add_runtime_dependency 'chozo', '>= 0.5.0'
23
+ s.add_runtime_dependency 'mixlib-log', '>= 1.3.0'
24
+ s.add_runtime_dependency 'mixlib-authentication', '>= 1.3.0'
25
25
  s.add_runtime_dependency 'addressable'
26
26
  s.add_runtime_dependency 'faraday', '>= 0.8.4'
27
27
  s.add_runtime_dependency 'activesupport', '>= 3.2.0'
28
+ s.add_runtime_dependency 'solve', '>= 0.4.1'
28
29
  s.add_runtime_dependency 'celluloid'
29
30
  s.add_runtime_dependency 'net-ssh'
30
31
  s.add_runtime_dependency 'erubis'
@@ -22,6 +22,10 @@ def setup_rspec
22
22
  Ridley.logger = nil
23
23
  Celluloid.logger = nil
24
24
  end
25
+
26
+ config.before(:each) do
27
+ clean_tmp_path
28
+ end
25
29
  end
26
30
  end
27
31
 
@@ -106,7 +106,7 @@ shared_examples_for "a Ridley Resource" do |resource_klass|
106
106
 
107
107
  it "sends a create message to the implementing class" do
108
108
  updated = double('updated')
109
- updated.stub(:attributes).and_return(Hash.new)
109
+ updated.stub(:_attributes_).and_return(Hash.new)
110
110
  subject.class.should_receive(:create).with(client, subject).and_return(updated)
111
111
 
112
112
  subject.save
@@ -116,7 +116,7 @@ shared_examples_for "a Ridley Resource" do |resource_klass|
116
116
  it "sends the update message to self" do
117
117
  updated = double('updated')
118
118
  updated.stub(:[]).and_return(Hash.new)
119
- updated.stub(:attributes).and_return(Hash.new)
119
+ updated.stub(:_attributes_).and_return(Hash.new)
120
120
  subject.class.should_receive(:create).and_raise(Ridley::Errors::HTTPConflict.new(updated))
121
121
  subject.should_receive(:update).and_return(updated)
122
122
 
@@ -141,7 +141,7 @@ shared_examples_for "a Ridley Resource" do |resource_klass|
141
141
  let(:updated) do
142
142
  updated = double('updated')
143
143
  updated.stub(:[]).and_return(Hash.new)
144
- updated.stub(:attributes).and_return(Hash.new)
144
+ updated.stub(:_attributes_).and_return(Hash.new)
145
145
  updated
146
146
  end
147
147
 
@@ -173,14 +173,14 @@ shared_examples_for "a Ridley Resource" do |resource_klass|
173
173
  it "returns the value of the chef_id attribute" do
174
174
  subject.class.attribute(:name)
175
175
  subject.class.stub(:chef_id) { :name }
176
- subject.attributes = { name: "reset" }
176
+ subject.mass_assign(name: "reset")
177
177
 
178
178
  subject.chef_id.should eql("reset")
179
179
  end
180
180
  end
181
181
 
182
182
  describe "#reload" do
183
- let(:updated_subject) { double('updated_subject', attributes: { fake_attribute: "some_value" }) }
183
+ let(:updated_subject) { double('updated_subject', _attributes_: { fake_attribute: "some_value" }) }
184
184
 
185
185
  before(:each) do
186
186
  subject.class.attribute(:fake_attribute)
@@ -194,8 +194,7 @@ shared_examples_for "a Ridley Resource" do |resource_klass|
194
194
  it "sets the attributes of self to include those of the reloaded object" do
195
195
  subject.reload
196
196
 
197
- subject.attributes.should have_key(:fake_attribute)
198
- subject.attributes[:fake_attribute].should eql("some_value")
197
+ subject.get_attribute(:fake_attribute).should eql("some_value")
199
198
  end
200
199
  end
201
200
  end
@@ -4,8 +4,17 @@ module Ridley
4
4
  Pathname.new(File.expand_path('../../../', __FILE__))
5
5
  end
6
6
 
7
+ def clean_tmp_path
8
+ FileUtils.rm_rf(tmp_path)
9
+ FileUtils.mkdir_p(tmp_path)
10
+ end
11
+
7
12
  def fixtures_path
8
13
  app_root_path.join('spec/fixtures')
9
14
  end
15
+
16
+ def tmp_path
17
+ app_root_path.join('spec/tmp')
18
+ end
10
19
  end
11
20
  end
@@ -22,4 +22,27 @@ describe Ridley::Connection do
22
22
  subject.api_type.should eql(:hosted)
23
23
  end
24
24
  end
25
+
26
+ describe "#stream" do
27
+ let(:target) { "http://test.it/file" }
28
+ let(:destination) { tmp_path.join("test.file") }
29
+ let(:contents) { "SOME STRING STUFF\nHERE.\n" }
30
+
31
+ before(:each) do
32
+ stub_request(:get, "http://test.it/file").
33
+ to_return(status: 200, body: contents)
34
+ end
35
+
36
+ it "creates a destination file on disk" do
37
+ subject.stream(target, destination)
38
+
39
+ File.exist?(destination).should be_true
40
+ end
41
+
42
+ it "contains the contents of the response body" do
43
+ subject.stream(target, destination)
44
+
45
+ File.read(destination).should include(contents)
46
+ end
47
+ end
25
48
  end
@@ -3,12 +3,28 @@ require 'spec_helper'
3
3
  describe Ridley::Middleware::ChefAuth do
4
4
  let(:server_url) { "https://api.opscode.com/organizations/vialstudios/" }
5
5
 
6
+ describe "ClassMethods" do
7
+ subject { described_class }
8
+
9
+ describe "#authentication_headers" do
10
+ let(:client_name) { "reset" }
11
+ let(:client_key) { fixtures_path.join("reset.pem") }
12
+
13
+ it "returns a Hash of authentication headers" do
14
+ options = {
15
+ http_method: "GET",
16
+ host: "https://api.opscode.com",
17
+ path: "/something.file"
18
+ }
19
+ subject.authentication_headers(client_name, client_key, options).should be_a(Hash)
20
+ end
21
+ end
22
+ end
23
+
6
24
  subject do
7
25
  Faraday.new(server_url) do |conn|
8
26
  conn.request :chef_auth, "reset", "/Users/reset/.chef/reset.pem"
9
27
  conn.adapter Faraday.default_adapter
10
28
  end
11
29
  end
12
-
13
- pending
14
30
  end
@@ -82,20 +82,6 @@ describe Ridley::Resource do
82
82
  Class.new(Ridley::Resource).new(connection)
83
83
  end
84
84
 
85
- describe "#attributes=" do
86
- subject do
87
- Class.new(Ridley::Resource) do
88
- attribute :name
89
- end.new(connection)
90
- end
91
-
92
- it "assigns the hash of attributes to the objects attributes" do
93
- subject.attributes = { name: "reset" }
94
-
95
- subject.attributes[:name].should eql("reset")
96
- end
97
- end
98
-
99
85
  describe "comparable" do
100
86
  subject do
101
87
  Class.new(Ridley::Resource) do
@@ -112,8 +98,8 @@ describe Ridley::Resource do
112
98
 
113
99
  context "given two objects with the same value for their 'chef_id'" do
114
100
  before(:each) do
115
- one.attributes = { name: "reset", other_extra: "stuff" }
116
- two.attributes = { name: "reset", extra: "stuff" }
101
+ one.mass_assign(name: "reset", other_extra: "stuff")
102
+ two.mass_assign(name: "reset", extra: "stuff")
117
103
  end
118
104
 
119
105
  it "is equal" do
@@ -123,8 +109,8 @@ describe Ridley::Resource do
123
109
 
124
110
  context "given two objects with different values for their 'chef_id'" do
125
111
  before(:each) do
126
- one.attributes = { name: "jamie", other_extra: "stuff" }
127
- two.attributes = { name: "winsor", extra: "stuff" }
112
+ one.mass_assign(name: "jamie", other_extra: "stuff")
113
+ two.mass_assign(name: "winsor", extra: "stuff")
128
114
  end
129
115
 
130
116
  it "is not equal" do
@@ -149,8 +135,8 @@ describe Ridley::Resource do
149
135
 
150
136
  context "given an array of objects with the same value for their 'chef_id'" do
151
137
  let(:nodes) do
152
- one.attributes = { name: "reset", other_extra: "stuff" }
153
- two.attributes = { name: "reset", extra: "stuff" }
138
+ one.mass_assign(name: "reset", other_extra: "stuff")
139
+ two.mass_assign(name: "reset", extra: "stuff")
154
140
 
155
141
  [ one, two ]
156
142
  end
@@ -162,8 +148,8 @@ describe Ridley::Resource do
162
148
 
163
149
  context "given an array of objects with different values for their 'chef_id'" do
164
150
  let(:nodes) do
165
- one.attributes = { name: "jamie", other_extra: "stuff" }
166
- two.attributes = { name: "winsor", extra: "stuff" }
151
+ one.mass_assign(name: "jamie", other_extra: "stuff")
152
+ two.mass_assign(name: "winsor", extra: "stuff")
167
153
 
168
154
  [ one, two ]
169
155
  end
@@ -1,5 +1,259 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Ridley::CookbookResource do
4
- pending
4
+ let(:client) { double('client', connection: double('connection')) }
5
+
6
+ subject { described_class.new(client) }
7
+
8
+ describe "ClassMethods" do
9
+ let(:server_url) { "https://api.opscode.com/organizations/vialstudios" }
10
+ let(:client_name) { "reset" }
11
+ let(:client_key) { fixtures_path.join("reset.pem") }
12
+
13
+ let(:client) do
14
+ Ridley.new(
15
+ server_url: server_url,
16
+ client_name: client_name,
17
+ client_key: client_key
18
+ )
19
+ end
20
+
21
+ describe "::all" do
22
+ subject { described_class.all(client) }
23
+
24
+ before(:each) do
25
+ stub_request(:get, File.join(server_url, "cookbooks")).
26
+ to_return(status: 200, body: {
27
+ "ant" => {
28
+ "url" => "https://api.opscode.com/organizations/vialstudios/cookbooks/ant",
29
+ "versions" => [
30
+ {
31
+ "url" => "https://api.opscode.com/organizations/vialstudios/cookbooks/ant/0.10.1",
32
+ "version" => "0.10.1"
33
+ }
34
+ ]
35
+ },
36
+ "apache2" => {
37
+ "url" => "https://api.opscode.com/organizations/vialstudios/cookbooks/apache2",
38
+ "versions" => [
39
+ {
40
+ "url" => "https://api.opscode.com/organizations/vialstudios/cookbooks/apache2/1.4.0",
41
+ "version" => "1.4.0"
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ )
47
+ end
48
+
49
+ it "returns a Hash" do
50
+ subject.should be_a(Hash)
51
+ end
52
+
53
+ it "contains a key for each cookbook" do
54
+ subject.should include("ant")
55
+ subject.should include("apache2")
56
+ end
57
+
58
+ it "contains an array of versions for each cookbook" do
59
+ subject["ant"].should be_a(Array)
60
+ subject["ant"].should have(1).item
61
+ subject["ant"].should include("0.10.1")
62
+ subject["apache2"].should be_a(Array)
63
+ subject["apache2"].should have(1).item
64
+ subject["apache2"].should include("1.4.0")
65
+ end
66
+ end
67
+
68
+ describe "::delete" do
69
+ let(:name) { "ant" }
70
+ let(:version) { "1.0.0" }
71
+
72
+ it "sends a DELETE to the cookbook version URL" do
73
+ stub_request(:delete, File.join(server_url, "cookbooks", name, version)).
74
+ to_return(status: 200, body: {})
75
+
76
+ described_class.delete(client, name, version)
77
+ end
78
+
79
+ context "when :purge is true" do
80
+ it "appends ?purge=true to the end of the URL" do
81
+ stub_request(:delete, File.join(server_url, "cookbooks", name, "#{version}?purge=true")).
82
+ to_return(status: 200, body: {})
83
+
84
+ described_class.delete(client, name, version, purge: true)
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "::delete_all" do
90
+ let(:name) { "ant" }
91
+ let(:versions) { ["1.0.0", "1.2.0", "2.0.0"] }
92
+ let(:options) { Hash.new }
93
+
94
+ subject { described_class }
95
+
96
+ it "deletes each version of the cookbook" do
97
+ subject.should_receive(:versions).with(client, name).and_return(versions)
98
+
99
+ versions.each do |version|
100
+ subject.should_receive(:delete).with(client, name, version, options)
101
+ end
102
+
103
+ subject.delete_all(client, name, options)
104
+ end
105
+ end
106
+
107
+ describe "::latest_version" do
108
+ let(:name) { "ant" }
109
+ subject { described_class }
110
+
111
+ before(:each) do
112
+ subject.should_receive(:versions).with(client, name).and_return(versions)
113
+ end
114
+
115
+ context "when the cookbook has no versions" do
116
+ let(:versions) { Array.new }
117
+
118
+ it "returns nil" do
119
+ subject.latest_version(client, name).should be_nil
120
+ end
121
+ end
122
+
123
+ context "when the cookbook has versions" do
124
+ let(:versions) do
125
+ [ "1.0.0", "1.2.0", "3.0.0", "1.4.1" ]
126
+ end
127
+
128
+ it "returns nil" do
129
+ subject.latest_version(client, name).should eql("3.0.0")
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "::versions" do
135
+ let(:cookbook) { "artifact" }
136
+ subject { described_class.versions(client, cookbook) }
137
+
138
+ before(:each) do
139
+ stub_request(:get, File.join(server_url, "cookbooks", cookbook)).
140
+ to_return(status: 200, body: {
141
+ cookbook => {
142
+ "versions" => [
143
+ {
144
+ "url" => "https://api.opscode.com/organizations/ridley/cookbooks/artifact/1.0.0",
145
+ "version" => "1.0.0"
146
+ },
147
+ {
148
+ "url" => "https://api.opscode.com/organizations/ridley/cookbooks/artifact/1.1.0",
149
+ "version" => "1.1.0"
150
+ },
151
+ {
152
+ "url" => "https://api.opscode.com/organizations/ridley/cookbooks/artifact/1.2.0",
153
+ "version" => "1.2.0"
154
+ }
155
+ ],
156
+ "url" => "https://api.opscode.com/organizations/ridley/cookbooks/artifact"}
157
+ }
158
+ )
159
+ end
160
+
161
+ it "returns an array" do
162
+ subject.should be_a(Array)
163
+ end
164
+
165
+ it "contains a version string for each cookbook version available" do
166
+ subject.should have(3).versions
167
+ subject.should include("1.0.0")
168
+ subject.should include("1.1.0")
169
+ subject.should include("1.2.0")
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "#download" do
175
+ it "downloads each file" do
176
+ subject.stub(:manifest) do
177
+ {
178
+ resources: [],
179
+ providers: [],
180
+ recipes: [
181
+ {
182
+ checksum: "aa3505d3eb8ce328ea84a4333df05b07",
183
+ name: "default.rb",
184
+ path: "recipes/default.rb",
185
+ specificity: "default",
186
+ url: "https://chef.lax1.riotgames.com/organizations/reset/cookbooks/ohai/1.0.2/files/aa3505d3eb8ce328ea84a4333df05b07"
187
+ }
188
+ ],
189
+ definitions: [],
190
+ libraries: [],
191
+ attributes: [],
192
+ files: [
193
+ {
194
+ checksum: "85bc3bb921efade3f2566a668ab4b639",
195
+ name: "README",
196
+ path: "files/default/plugins/README",
197
+ specificity: "plugins",
198
+ url: "https://chef.lax1.riotgames.com/organizations/reset/cookbooks/ohai/1.0.2/files/85bc3bb921efade3f2566a668ab4b639"
199
+ }
200
+ ],
201
+ templates: [],
202
+ root_files: []
203
+ }
204
+ end
205
+
206
+ subject.should_receive(:download_file).with(:recipes, "default.rb", anything)
207
+ subject.should_receive(:download_file).with(:files, "README", anything)
208
+
209
+ subject.download
210
+ end
211
+ end
212
+
213
+ describe "#download_file" do
214
+ let(:destination) { tmp_path.join('fake.file') }
215
+
216
+ before(:each) do
217
+ subject.stub(:root_files) { [ { name: 'metadata.rb', url: "http://test.it/file" } ] }
218
+ end
219
+
220
+ it "downloads the file from the file's url" do
221
+ client.connection.should_receive(:stream).with("http://test.it/file", destination)
222
+
223
+ subject.download_file(:root_file, "metadata.rb", destination)
224
+ end
225
+
226
+ context "when given an unknown filetype" do
227
+ it "raises an UnknownCookbookFileType error" do
228
+ expect {
229
+ subject.download_file(:not_existant, "default.rb", destination)
230
+ }.to raise_error(Ridley::Errors::UnknownCookbookFileType)
231
+ end
232
+ end
233
+
234
+ context "when the cookbook doesn't have the specified file" do
235
+ before(:each) do
236
+ subject.stub(:root_files) { Array.new }
237
+ end
238
+
239
+ it "returns nil" do
240
+ subject.download_file(:root_file, "metadata.rb", destination).should be_nil
241
+ end
242
+ end
243
+ end
244
+
245
+ describe "#manifest" do
246
+ it "returns a Hash" do
247
+ subject.manifest.should be_a(Hash)
248
+ end
249
+
250
+ it "has a key for each item in FILE_TYPES" do
251
+ subject.manifest.keys.should =~ described_class::FILE_TYPES
252
+ end
253
+
254
+ it "contains an empty array for each key" do
255
+ subject.manifest.should each be_a(Array)
256
+ subject.manifest.values.should each be_empty
257
+ end
258
+ end
5
259
  end