dnapi 1.1.74.jruby192.c
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/dnapi.rb +54 -0
- data/lib/dnapi/app.rb +130 -0
- data/lib/dnapi/component.rb +50 -0
- data/lib/dnapi/component_possessor.rb +49 -0
- data/lib/dnapi/components/addons.rb +26 -0
- data/lib/dnapi/components/apache.rb +13 -0
- data/lib/dnapi/components/cloudkick.rb +13 -0
- data/lib/dnapi/components/encrypted_backup.rb +12 -0
- data/lib/dnapi/components/exim.rb +10 -0
- data/lib/dnapi/components/monitor.rb +12 -0
- data/lib/dnapi/components/nagios.rb +28 -0
- data/lib/dnapi/components/newrelic.rb +12 -0
- data/lib/dnapi/components/passenger3.rb +13 -0
- data/lib/dnapi/components/ruby.rb +234 -0
- data/lib/dnapi/components/ssmtp.rb +10 -0
- data/lib/dnapi/components/stunneled.rb +13 -0
- data/lib/dnapi/components/volume.rb +32 -0
- data/lib/dnapi/cron.rb +5 -0
- data/lib/dnapi/db_stack.rb +92 -0
- data/lib/dnapi/ebuild_dep.rb +5 -0
- data/lib/dnapi/environment.rb +327 -0
- data/lib/dnapi/extensions.rb +32 -0
- data/lib/dnapi/gem_dep.rb +9 -0
- data/lib/dnapi/instance.rb +69 -0
- data/lib/dnapi/monitoring.rb +22 -0
- data/lib/dnapi/recipe.rb +27 -0
- data/lib/dnapi/ssl_cert.rb +13 -0
- data/lib/dnapi/stack.rb +111 -0
- data/lib/dnapi/struct.rb +149 -0
- data/lib/dnapi/test.rb +114 -0
- data/lib/dnapi/test/ext.rb +32 -0
- data/lib/dnapi/test/sweatshop.rb +148 -0
- data/lib/dnapi/version.rb +3 -0
- data/lib/dnapi/vhost.rb +24 -0
- data/spec/app_spec.rb +68 -0
- data/spec/component_spec.rb +66 -0
- data/spec/components/addons_spec.rb +33 -0
- data/spec/components/cloudkick_spec.rb +17 -0
- data/spec/components/nagios_spec.rb +42 -0
- data/spec/components/nodejs_spec.rb +27 -0
- data/spec/components/passenger3_spec.rb +12 -0
- data/spec/components/ruby_spec.rb +321 -0
- data/spec/components/stunneled.rb +15 -0
- data/spec/components/volume_spec.rb +21 -0
- data/spec/db_stack_spec.rb +111 -0
- data/spec/environment_spec.rb +227 -0
- data/spec/instance_spec.rb +52 -0
- data/spec/proxies.rb +143 -0
- data/spec/proxies_spec.rb +76 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/stack_spec.rb +105 -0
- data/spec/struct_spec.rb +100 -0
- metadata +181 -0
@@ -0,0 +1,227 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe DNApi::Environment do
|
4
|
+
|
5
|
+
def instance_info
|
6
|
+
@id ||= 0
|
7
|
+
@id += 1
|
8
|
+
{:id => @id,
|
9
|
+
:public_hostname => "public_host.#{@id}",
|
10
|
+
:private_hostname => "private_host.#{@id}"}
|
11
|
+
end
|
12
|
+
|
13
|
+
def legacy_provision_instance
|
14
|
+
require 'ostruct'
|
15
|
+
OpenStruct.new(instance_info)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#db_host" do
|
19
|
+
it 'is the public hostname of the solo instance if the environment consists of a solo instance' do
|
20
|
+
environment = DNApi::Environment.new
|
21
|
+
environment.build_instance(instance_info.merge(:role => :solo))
|
22
|
+
environment.db_host.should eql('public_host.1')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is the public hostname of the database server' do
|
26
|
+
environment = DNApi::Environment.new
|
27
|
+
db_instance_info = instance_info
|
28
|
+
environment.build_instance(db_instance_info.merge(:role => :db_master))
|
29
|
+
environment.db_host.should eql(db_instance_info[:public_hostname])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "responds to legacy 'api'" do
|
33
|
+
environment = DNApi::Environment.new
|
34
|
+
instance = legacy_provision_instance
|
35
|
+
environment.build_instance(:role => :db_master, :provisioned => instance)
|
36
|
+
environment.db_host.should eql(instance.public_hostname)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#db_slaves" do
|
41
|
+
it 'is an array of all instances with the db_slave role' do
|
42
|
+
environment = DNApi::Environment.new
|
43
|
+
environment.build_instance(instance_info.merge(:role => :app_master))
|
44
|
+
environment.build_instance(instance_info.merge(:role => :db_master))
|
45
|
+
environment.build_instance(instance_info.merge(:role => :db_slave))
|
46
|
+
environment.build_instance(instance_info.merge(:role => :db_slave))
|
47
|
+
environment.build_instance(instance_info.merge(:role => :db_slave))
|
48
|
+
environment.should have(3).db_slaves
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#utility_instances" do
|
53
|
+
it 'is an array of all instances with the utility_instances role' do
|
54
|
+
environment = DNApi::Environment.new
|
55
|
+
environment.build_instance(instance_info.merge(:role => :app_master))
|
56
|
+
environment.build_instance(instance_info.merge(:role => :db_master))
|
57
|
+
environment.build_instance(instance_info.merge(:role => :db_slave))
|
58
|
+
environment.build_instance(instance_info.merge(:role => :util, :name => "foo"))
|
59
|
+
environment.build_instance(instance_info.merge(:role => :util, :name => "bar"))
|
60
|
+
environment.should have(2).utility_instances
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#recipes' do
|
65
|
+
it 'includes the stack recipes' do
|
66
|
+
env = DNApi::Environment.new(:stack => DNApi::Stack::NginxMongrel)
|
67
|
+
env.build_app
|
68
|
+
env.recipes.should include(*DNApi::Stack::NginxMongrel.recipes)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'includes the app recipes' do
|
72
|
+
env = DNApi::Environment.new(:stack => DNApi::Stack::NginxMongrel)
|
73
|
+
env.build_app
|
74
|
+
env.recipes.should include(*DNApi::Recipe.defaults)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#mysql_backup_cron' do
|
79
|
+
it 'is nil if there is no backup_window' do
|
80
|
+
env = DNApi::Environment.new(:backup_window => 0, :db_stack => DNApi::DbStack::Mysql)
|
81
|
+
env.mysql_backup_cron.should be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'runs eybackup --quiet' do
|
85
|
+
env = DNApi::Environment.new(:backup_window => 1, :db_stack => DNApi::DbStack::Mysql)
|
86
|
+
env.mysql_backup_cron.command.should == 'eybackup --quiet'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'is 10 past the hour' do
|
90
|
+
env = DNApi::Environment.new(:backup_window => 1, :db_stack => DNApi::DbStack::Mysql)
|
91
|
+
env.mysql_backup_cron.minute.should == '10'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'is at 1 AM PST if the backup interal is 24 hours' do
|
95
|
+
env = DNApi::Environment.new(:backup_window => 1, :backup_interval => 24, :db_stack => DNApi::DbStack::Mysql)
|
96
|
+
env.mysql_backup_cron.hour.should == '1'
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'is at every other hour if the backup interval is 12 hours' do
|
100
|
+
env = DNApi::Environment.new(:backup_window => 1, :backup_interval => 12, :db_stack => DNApi::DbStack::Mysql)
|
101
|
+
env.mysql_backup_cron.hour.should == '*/12'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#snapshot_cron' do
|
106
|
+
it 'runs ey-snapshots --snapshot --quiet' do
|
107
|
+
env = DNApi::Environment.new(:backup_window => 1)
|
108
|
+
env.snapshot_cron.command.should == 'ey-snapshots --snapshot --quiet'
|
109
|
+
end
|
110
|
+
it 'is in the last half of the hour' do
|
111
|
+
env = DNApi::Environment.new(:backup_window => 1)
|
112
|
+
env.snapshot_cron.minute.should =~ %r{0/[3-5]\d}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#postgres_backup_cron' do
|
117
|
+
it 'runs eybackup -e postgresql --quiet' do
|
118
|
+
env = DNApi::Environment.new(:backup_window => 1, :db_stack => DNApi::DbStack::Postgres)
|
119
|
+
env.postgres_backup_cron.command.should == 'eybackup -e postgresql --quiet'
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'is 20 past the hour' do
|
123
|
+
env = DNApi::Environment.new(:backup_window => 1, :db_stack => DNApi::DbStack::Postgres)
|
124
|
+
env.postgres_backup_cron.minute.should == '20'
|
125
|
+
end
|
126
|
+
|
127
|
+
context "disabled backups" do
|
128
|
+
it 'returns nil when backups are disabled on Postgres DbStack' do
|
129
|
+
env = DNApi::Environment.new(:backup_window => 0, :db_stack => DNApi::DbStack::Postgres)
|
130
|
+
env.postgres_backup_cron.should be_nil
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'returns nil when backups are disabled on Postgres9 DbStack' do
|
134
|
+
env = DNApi::Environment.new(:backup_window => 0, :db_stack => DNApi::DbStack::Postgres9)
|
135
|
+
env.postgres_backup_cron.should be_nil
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'returns nil when backups are disabled on Postgres91 DbStack' do
|
139
|
+
env = DNApi::Environment.new(:backup_window => 0, :db_stack => DNApi::DbStack::Postgres91)
|
140
|
+
env.postgres_backup_cron.should be_nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "has newrelic" do
|
146
|
+
env = DNApi::Environment.new
|
147
|
+
|
148
|
+
env.newrelic_key = "foo"
|
149
|
+
env.newrelic_key.should == "foo"
|
150
|
+
|
151
|
+
env.build_app(:newrelic => true)
|
152
|
+
env.apps.first.newrelic?.should be_true
|
153
|
+
|
154
|
+
env.build_app.newrelic?.should be_false
|
155
|
+
end
|
156
|
+
|
157
|
+
it "ignores disabled instances when listing enabled app servers hostnames" do
|
158
|
+
env = DNApi.gen(:default, 'nginx_passenger', ['rails'])
|
159
|
+
env.build_instance(instance_info.merge(:role => :db_master, :enabled => false))
|
160
|
+
env.build_instance(instance_info.merge(:role => :app_master, :enabled => false))
|
161
|
+
instance = env.build_instance(instance_info.merge(:role => :app, :enabled => false))
|
162
|
+
env.enabled_app_servers_hostnames.should be_empty
|
163
|
+
|
164
|
+
dna = JSON.parse(instance.to_dna.to_json)
|
165
|
+
dna["members"].should be_empty
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#backup_window' do
|
169
|
+
it 'should default to 14' do
|
170
|
+
DNApi::Environment.new.backup_window.should == 14
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#dna_for_instance" do
|
175
|
+
it "raises an error when the instance is not found" do
|
176
|
+
env = DNApi.gen(:default, 'nginx_passenger', [])
|
177
|
+
instance = env.build_instance(instance_info.merge(:role => :solo))
|
178
|
+
lambda { DNApi::Environment.new.dna_for_instance(instance) }.
|
179
|
+
should raise_error(DNApi::InstanceNotFound)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
specify "monitoring" do
|
184
|
+
default = DNApi::Environment.new
|
185
|
+
default.monitoring.should be_monit
|
186
|
+
default.monitoring = "god"
|
187
|
+
default.monitoring.should be_god
|
188
|
+
|
189
|
+
monit = DNApi::Environment.new(:monitoring => "monit").monitoring
|
190
|
+
monit.should be_monit
|
191
|
+
monit.name.should == "monit"
|
192
|
+
monit.label.should == "Monit"
|
193
|
+
|
194
|
+
god = DNApi::Environment.new(:monitoring => "god").monitoring
|
195
|
+
god.should be_god
|
196
|
+
god.name.should == "god"
|
197
|
+
god.label.should == "god"
|
198
|
+
end
|
199
|
+
|
200
|
+
specify "components" do
|
201
|
+
env = DNApi::Environment.new
|
202
|
+
env.components.should be_empty
|
203
|
+
env.components << DNApi::Component[:god].new
|
204
|
+
env.has_component?(:god).should be_true
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "#components" do
|
208
|
+
it 'dumps components into a hash' do
|
209
|
+
env = DNApi::Environment.new
|
210
|
+
env.add_component(:god)
|
211
|
+
DNApi::Environment.from(JSON.parse(env.to_json)).components.should_not be_empty
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "#ruby_component" do
|
216
|
+
before(:each) do
|
217
|
+
@env = DNApi::Environment.new
|
218
|
+
end
|
219
|
+
|
220
|
+
DNApi::Components::RubyVersion.all.each do |ruby_component|
|
221
|
+
it "returns #{ruby_component.key_id} when appropriate" do
|
222
|
+
@env.add_component(ruby_component.key_id)
|
223
|
+
@env.ruby_component.should == @env.component(ruby_component.key_id)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe DNApi::Instance do
|
4
|
+
before(:each) do
|
5
|
+
@environment = DNApi::Environment.new
|
6
|
+
@instance = @environment.build_instance(:id => 'default', :role => :app_master)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'has selectors for environment data' do
|
10
|
+
@instance.apps.should == @environment.apps
|
11
|
+
@instance.recipes.should == @environment.recipes
|
12
|
+
@instance.solo?.should == @environment.solo?
|
13
|
+
@instance.ssh_username == @environment.ssh_username
|
14
|
+
@instance.ssh_password == @environment.ssh_password
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has newrelic attributes when it has the :newrelic component" do
|
18
|
+
@instance.add_component(:newrelic, :seed => 'bar', :token => 'sekretz')
|
19
|
+
|
20
|
+
@instance.newrelic_seed.should == "bar"
|
21
|
+
@instance.newrelic_token.should == "sekretz"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "lacks newrelic attributes when it lacks the :newrelic component" do
|
25
|
+
@instance.should_not have_component(:newrelic)
|
26
|
+
@instance.newrelic_token.should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "allows adding a ssmtp component" do
|
30
|
+
@instance.add_component(:ssmtp)
|
31
|
+
@instance.should have_component(:ssmtp)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "allows adding a ssmtp component" do
|
35
|
+
@instance.add_component(:exim, :user => "test", :password => "suck", :host => "example.org", :outbound_host => "sendgrid")
|
36
|
+
|
37
|
+
@instance.should have_component(:exim)
|
38
|
+
|
39
|
+
exim = @instance.component(:exim)
|
40
|
+
exim.user.should == "test"
|
41
|
+
exim.password.should == "suck"
|
42
|
+
exim.host.should == "example.org"
|
43
|
+
exim.outbound_host.should == "sendgrid"
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'allows adding multiple volume components' do
|
47
|
+
@instance.add_component(:ebs_volume, :mountpoint => '/data', :size => 5 * 1024 * 1024)
|
48
|
+
@instance.add_component(:ebs_volume, :mountpoint => '/db', :size => 5 * 1024 * 1024)
|
49
|
+
|
50
|
+
@instance.volumes.size.should == 2
|
51
|
+
end
|
52
|
+
end
|
data/spec/proxies.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
class Object
|
2
|
+
def deep_clone
|
3
|
+
Marshal.load(Marshal.dump(self))
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module DNApi
|
8
|
+
class ArrayProxy
|
9
|
+
def self.build(array)
|
10
|
+
new(array).build
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(array)
|
14
|
+
@array = array
|
15
|
+
end
|
16
|
+
|
17
|
+
def build
|
18
|
+
@positions = (0..(@array.size - 1)).to_a
|
19
|
+
@original_array = @array.deep_clone
|
20
|
+
@array.map! do |value|
|
21
|
+
case value
|
22
|
+
when Hash
|
23
|
+
HashProxy.build(value)
|
24
|
+
when Array
|
25
|
+
ArrayProxy.build(value)
|
26
|
+
else
|
27
|
+
value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def index_of(&block)
|
34
|
+
@original_array.each_with_index do |value,i|
|
35
|
+
return i if yield value
|
36
|
+
end
|
37
|
+
raise "Could not find the element in #{inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def size
|
41
|
+
@array.size
|
42
|
+
end
|
43
|
+
|
44
|
+
def empty?
|
45
|
+
@array.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def fully_accessed?
|
49
|
+
@positions.empty? && unaccessed_children.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
def unaccessed
|
53
|
+
{:positions => @positions, :children => unaccessed_children}
|
54
|
+
end
|
55
|
+
|
56
|
+
def unaccessed_children
|
57
|
+
foo = {}
|
58
|
+
@array.each_with_index do |value,i|
|
59
|
+
case value
|
60
|
+
when HashProxy, ArrayProxy
|
61
|
+
foo[i] = value.unaccessed unless value.fully_accessed?
|
62
|
+
when Hash, Array
|
63
|
+
raise "This should be a #{value.class}Proxy: #{value.inspect}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
foo
|
67
|
+
end
|
68
|
+
|
69
|
+
def [](position)
|
70
|
+
@positions.delete(position)
|
71
|
+
@array[position]
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect
|
75
|
+
@array.inspect
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class HashProxy
|
80
|
+
def self.build(hash)
|
81
|
+
new(hash).build
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(hash)
|
85
|
+
@hash = hash
|
86
|
+
end
|
87
|
+
|
88
|
+
def build
|
89
|
+
@keys = @hash.keys
|
90
|
+
@hash.each do |key,value|
|
91
|
+
case value
|
92
|
+
when Hash
|
93
|
+
@hash[key] = HashProxy.build(value)
|
94
|
+
when Array
|
95
|
+
@hash[key] = ArrayProxy.build(value)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_key?(key)
|
102
|
+
@hash.has_key?(key)
|
103
|
+
end
|
104
|
+
|
105
|
+
def keys
|
106
|
+
@hash.keys
|
107
|
+
end
|
108
|
+
|
109
|
+
def any?
|
110
|
+
@hash.any?
|
111
|
+
end
|
112
|
+
|
113
|
+
def fully_accessed?
|
114
|
+
@keys.empty? && unaccessed_children.empty?
|
115
|
+
end
|
116
|
+
|
117
|
+
def unaccessed
|
118
|
+
{:keys => @keys, :children => unaccessed_children}
|
119
|
+
end
|
120
|
+
|
121
|
+
def unaccessed_children
|
122
|
+
foo = {}
|
123
|
+
@hash.each do |key,value|
|
124
|
+
case value
|
125
|
+
when HashProxy, ArrayProxy
|
126
|
+
foo[key] = value.unaccessed unless value.fully_accessed?
|
127
|
+
when Hash, Array
|
128
|
+
raise "This should be a #{value.class}Proxy: #{key.inspect} #{value.inspect}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
foo
|
132
|
+
end
|
133
|
+
|
134
|
+
def [](key)
|
135
|
+
@keys.delete(key)
|
136
|
+
@hash[key]
|
137
|
+
end
|
138
|
+
|
139
|
+
def inspect
|
140
|
+
@hash.inspect
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/proxies'
|
2
|
+
require 'pp'
|
3
|
+
require 'sexp_processor' #defines Object#deep_copy
|
4
|
+
|
5
|
+
describe DNApi::HashProxy do
|
6
|
+
describe "with no elements" do
|
7
|
+
it "is fully accessed" do
|
8
|
+
DNApi::HashProxy.build({}).should be_fully_accessed
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "with a single element" do
|
13
|
+
before(:each) do
|
14
|
+
@hash = DNApi::HashProxy.build({:foo => :bar})
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is not fully accessed" do
|
18
|
+
@hash.should_not be_fully_accessed
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "which has been accessed" do
|
22
|
+
it "is fully accessed" do
|
23
|
+
@hash[:foo]
|
24
|
+
@hash.should be_fully_accessed
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "with a nested hash" do
|
30
|
+
it "should not be fully accessed unless it's children have been fully accessed" do
|
31
|
+
@hash = DNApi::HashProxy.build({:foo => {:bar => :baz}})
|
32
|
+
lambda { @hash[:foo] }.should_not change { @hash.fully_accessed? }
|
33
|
+
@hash.unaccessed[:keys].should be_empty
|
34
|
+
@hash.unaccessed[:children].should == {:foo => {:keys => [:bar], :children => {}}}
|
35
|
+
@hash[:foo][:bar]
|
36
|
+
@hash.should be_fully_accessed
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "with a nested array" do
|
41
|
+
it "should not be fully accessed until it's elements have been accessed" do
|
42
|
+
@hash = DNApi::HashProxy.build({:foo => [:bar, :baz]})
|
43
|
+
lambda { @hash[:foo] }.should_not change { @hash.fully_accessed? }
|
44
|
+
@hash.unaccessed[:keys].should be_empty
|
45
|
+
@hash.unaccessed[:children].should == {:foo => {:positions => [0, 1], :children => {}}}
|
46
|
+
@hash[:foo][0]
|
47
|
+
@hash[:foo][1]
|
48
|
+
@hash.should be_fully_accessed
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe DNApi::ArrayProxy do
|
54
|
+
describe "with no elements" do
|
55
|
+
it "is fully accessed" do
|
56
|
+
DNApi::ArrayProxy.build([]).should be_fully_accessed
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "with a single element" do
|
61
|
+
before(:each) do
|
62
|
+
@array = DNApi::ArrayProxy.build([:foo])
|
63
|
+
end
|
64
|
+
|
65
|
+
it "is not fully accessed" do
|
66
|
+
@array.should_not be_fully_accessed
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "which has been accessed" do
|
70
|
+
it "is fully accessed" do
|
71
|
+
@array[0]
|
72
|
+
@array.should be_fully_accessed
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|