bosh_vsphere_cpi 0.4.9 → 0.5.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.
@@ -0,0 +1,72 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources::Datacenter do
6
+ before(:each) do
7
+ @client = mock(:client)
8
+ VSphereCloud::Config.client = @client
9
+ VSphereCloud::Config.mem_overcommit = 1.0
10
+ end
11
+
12
+ describe :initialize do
13
+ it "should create a datacenter" do
14
+ dc_mob = mock(:dc_mob)
15
+ cluster_mob = mock(:cluster_mob)
16
+
17
+ @client.should_receive(:find_by_inventory_path).with("TEST_DC").
18
+ and_return(dc_mob)
19
+ @client.should_receive(:get_managed_objects).
20
+ with(VimSdk::Vim::ClusterComputeResource,
21
+ {:root=>dc_mob, :include_name=>true}).
22
+ and_return({"foo" => cluster_mob})
23
+ @client.should_receive(:get_properties).
24
+ with([cluster_mob], VimSdk::Vim::ClusterComputeResource,
25
+ %w(name datastore resourcePool host), {:ensure_all => true}).
26
+ and_return({cluster_mob => {:foo => :bar}})
27
+
28
+ folder_config = VSphereCloud::Config::FolderConfig.new
29
+ folder_config.vm = "vms"
30
+ folder_config.template = "templates"
31
+ folder_config.shared = false
32
+ cluster_config = VSphereCloud::Config::ClusterConfig.new("foo")
33
+ datastore_config = VSphereCloud::Config::DatastoreConfig.new
34
+ datastore_config.disk_path = "bosh_disks"
35
+
36
+ dc_config = mock(:dc_config)
37
+ dc_config.stub(:name).and_return("TEST_DC")
38
+ dc_config.stub(:folders).and_return(folder_config)
39
+ dc_config.stub(:clusters).and_return({"foo" => cluster_config})
40
+ dc_config.stub(:datastores).and_return(datastore_config)
41
+
42
+ vm_folder = mock(:vm_folder)
43
+ VSphereCloud::Resources::Folder.stub!(:new).
44
+ with(an_instance_of(VSphereCloud::Resources::Datacenter),
45
+ "vms", false).
46
+ and_return(vm_folder)
47
+
48
+ template_folder = mock(:template_folder)
49
+ VSphereCloud::Resources::Folder.stub!(:new).
50
+ with(an_instance_of(VSphereCloud::Resources::Datacenter),
51
+ "templates", false).
52
+ and_return(template_folder)
53
+
54
+ cluster = mock(:cluster)
55
+ cluster.stub(:name).and_return("foo")
56
+ VSphereCloud::Resources::Cluster.stub!(:new).
57
+ with(an_instance_of(VSphereCloud::Resources::Datacenter),
58
+ cluster_config, {:foo => :bar}).
59
+ and_return(cluster)
60
+
61
+ datacenter = VSphereCloud::Resources::Datacenter.new(dc_config)
62
+ datacenter.mob.should == dc_mob
63
+ datacenter.clusters.should == {"foo" => cluster}
64
+ datacenter.vm_folder.should == vm_folder
65
+ datacenter.template_folder.should == template_folder
66
+ datacenter.config.should == dc_config
67
+ datacenter.name.should == "TEST_DC"
68
+ datacenter.disk_path.should == "bosh_disks"
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,43 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources::Datastore do
6
+ before(:each) do
7
+ @client = mock(:client)
8
+ VSphereCloud::Config.client = @client
9
+ VSphereCloud::Config.mem_overcommit = 1.0
10
+ end
11
+
12
+ describe :initialize do
13
+ it "should create a datastore" do
14
+ ds_mob = mock(:ds_mob)
15
+ datastore = VSphereCloud::Resources::Datastore.new({
16
+ :obj => ds_mob,
17
+ "name" => "foo_lun",
18
+ "summary.capacity" => 16 * 1024 * 1024 * 1024,
19
+ "summary.freeSpace" => 8 * 1024 * 1024 * 1024
20
+ })
21
+
22
+ datastore.mob.should == ds_mob
23
+ datastore.total_space.should == 16384
24
+ datastore.free_space.should == 8192
25
+ datastore.synced_free_space.should == 8192
26
+ datastore.allocated_after_sync.should == 0
27
+ end
28
+ end
29
+
30
+ describe :allocate do
31
+ it "should allocate space" do
32
+ ds_mob = mock(:ds_mob)
33
+ datastore = VSphereCloud::Resources::Datastore.new({
34
+ :obj => ds_mob,
35
+ "name" => "foo_lun",
36
+ "summary.capacity" => 16 * 1024 * 1024 * 1024,
37
+ "summary.freeSpace" => 8 * 1024 * 1024 * 1024
38
+ })
39
+ datastore.allocate(1024)
40
+ datastore.free_space.should == 7168
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources::Folder do
6
+ before(:each) do
7
+ @client = mock(:client)
8
+ VSphereCloud::Config.client = @client
9
+ VSphereCloud::Config.mem_overcommit = 1.0
10
+ end
11
+
12
+ describe :initialize do
13
+ it "should create a folder" do
14
+ datacenter = mock(:datacenter)
15
+ datacenter.stub(:name).and_return("TEST_DC")
16
+
17
+ folder_mob = mock(:folder_mob)
18
+
19
+ @client.should_receive(:find_by_inventory_path).with(%w(TEST_DC vm foo)).
20
+ and_return(folder_mob)
21
+
22
+ folder = VSphereCloud::Resources::Folder.new(datacenter, "foo", false)
23
+ folder.mob.should == folder_mob
24
+ folder.name.should == "foo"
25
+ end
26
+
27
+ it "should create a namespaced folder" do
28
+ datacenter = mock(:datacenter)
29
+ datacenter.stub(:name).and_return("TEST_DC")
30
+
31
+ folder_mob = mock(:folder_mob)
32
+ @client.should_receive(:find_by_inventory_path).with(%w(TEST_DC vm foo)).
33
+ and_return(folder_mob)
34
+
35
+ ns_folder_mob = mock(:ns_folder_mob)
36
+ @client.should_receive(:find_by_inventory_path).
37
+ with(["TEST_DC", "vm", %w(foo 123)]).and_return(ns_folder_mob)
38
+
39
+ folder = VSphereCloud::Resources::Folder.new(datacenter, "foo", true)
40
+ folder.mob.should == ns_folder_mob
41
+ folder.name.should == %w(foo 123)
42
+ end
43
+
44
+ it "should create a namespaced folder and create it in vSphere" do
45
+ datacenter = mock(:datacenter)
46
+ datacenter.stub(:name).and_return("TEST_DC")
47
+
48
+ folder_mob = mock(:folder_mob)
49
+ @client.should_receive(:find_by_inventory_path).with(%w(TEST_DC vm foo)).
50
+ and_return(folder_mob)
51
+ @client.should_receive(:find_by_inventory_path).
52
+ with(["TEST_DC", "vm", %w(foo 123)]).and_return(nil)
53
+
54
+ ns_folder_mob = mock(:ns_folder_mob)
55
+ folder_mob.should_receive(:create_folder).with("123").
56
+ and_return(ns_folder_mob)
57
+
58
+ folder = VSphereCloud::Resources::Folder.new(datacenter, "foo", true)
59
+ folder.mob.should == ns_folder_mob
60
+ folder.name.should == %w(foo 123)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources::ResourcePool do
6
+ before(:each) do
7
+ @client = mock(:client)
8
+ VSphereCloud::Config.client = @client
9
+ VSphereCloud::Config.mem_overcommit = 1.0
10
+ end
11
+
12
+ describe :initialize do
13
+ it "should create a resource pool" do
14
+ cluster = mock(:cluster)
15
+ cluster_config = VSphereCloud::Config::ClusterConfig.new("foo")
16
+ cluster.stub(:config).and_return(cluster_config)
17
+ root_resource_pool_mob = mock(:root_resource_pool)
18
+
19
+ resource_pool = VSphereCloud::Resources::ResourcePool.new(
20
+ cluster, root_resource_pool_mob)
21
+ resource_pool.mob.should == root_resource_pool_mob
22
+ end
23
+
24
+ it "should create a resource pool with the specified name" do
25
+ cluster = mock(:cluster)
26
+ cluster_config = VSphereCloud::Config::ClusterConfig.new(
27
+ {"foo" => {"resource_pool" => "bar"}})
28
+ cluster.stub(:config).and_return(cluster_config)
29
+ root_resource_pool_mob = mock(:root_resource_pool)
30
+
31
+ child_resource_pool_mob = mock(:child_resource_pool_mob)
32
+ @client.should_receive(:get_managed_object).
33
+ with(VimSdk::Vim::ResourcePool,
34
+ {:root=> root_resource_pool_mob, :name=>"bar"}).
35
+ and_return(child_resource_pool_mob)
36
+
37
+ resource_pool = VSphereCloud::Resources::ResourcePool.new(
38
+ cluster, root_resource_pool_mob)
39
+ resource_pool.mob.should == child_resource_pool_mob
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources::Scorer do
6
+
7
+ def create_datastores(sizes)
8
+ datastores = {}
9
+ sizes.each_with_index do |size, i|
10
+ datastore = mock(:datastore)
11
+ datastore.stub(:free_space).and_return(size)
12
+ datastores["ds_#{i}"] = datastore
13
+ end
14
+ datastores
15
+ end
16
+
17
+ def create_cluster(memory, ephemeral, persistent, shared)
18
+ cluster = mock(:cluster)
19
+ cluster.stub(:name).and_return("foo")
20
+ cluster.stub(:free_memory).and_return(memory)
21
+ cluster.stub(:ephemeral_datastores).
22
+ and_return(create_datastores(ephemeral))
23
+ cluster.stub(:persistent_datastores).
24
+ and_return(create_datastores(persistent))
25
+ cluster.stub(:shared_datastores).
26
+ and_return(create_datastores(shared))
27
+ cluster
28
+ end
29
+
30
+ describe :score do
31
+ it "should return 0 when memory is not available" do
32
+ cluster = create_cluster(500, [32 * 1024], [32 * 1024], [])
33
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 512, 1, [])
34
+ scorer.score.should == 0
35
+ end
36
+
37
+ it "should return 0 when ephemeral space is not available" do
38
+ cluster = create_cluster(16 * 1024, [512], [32 * 1024], [])
39
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 1, 1024, [])
40
+ scorer.score.should == 0
41
+ end
42
+
43
+ it "should return 0 when persistent space is not available" do
44
+ cluster = create_cluster(16 * 1024, [32 * 1024], [512], [])
45
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 1, 1, [1024])
46
+ scorer.score.should == 0
47
+ end
48
+
49
+ it "should calculate memory bound score" do
50
+ cluster = create_cluster(16 * 1024, [32 * 1024], [32 * 1024], [])
51
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 512, 1, [])
52
+ scorer.score.should == 31
53
+ end
54
+
55
+ it "should calculate ephemeral bound score" do
56
+ cluster = create_cluster(16 * 1024, [32 * 1024], [32 * 1024], [])
57
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 1, 512, [])
58
+ scorer.score.should == 62
59
+ end
60
+
61
+ it "should calculate persistent bound score" do
62
+ cluster = create_cluster(16 * 1024, [32 * 1024], [32 * 1024], [])
63
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 1, 1, [512])
64
+ scorer.score.should == 62
65
+ end
66
+
67
+ it "should calculate shared bound score" do
68
+ cluster = create_cluster(16 * 1024, [], [], [32 * 1024])
69
+ scorer = VSphereCloud::Resources::Scorer.new(cluster, 1, 1024, [512])
70
+ scorer.score.should == 20
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources::Util do
6
+ describe :average_csv do
7
+ it "should compute the average integer value" do
8
+ VSphereCloud::Resources::Util.average_csv("1,2,3").should == 2
9
+ end
10
+
11
+ it "should compute the average float value" do
12
+ VSphereCloud::Resources::Util.average_csv("1.5,2.5,3.5").should == 2.5
13
+ end
14
+
15
+ it "should return 0 when there is no data" do
16
+ VSphereCloud::Resources::Util.average_csv("").should == 0
17
+ end
18
+ end
19
+
20
+ describe :weighted_random do
21
+ it "should calculate the weighted random" do
22
+ util = VSphereCloud::Resources::Util
23
+ util.should_receive(:rand).with(3).and_return(0)
24
+ util.should_receive(:rand).with(3).and_return(1)
25
+ util.should_receive(:rand).with(3).and_return(2)
26
+ util.weighted_random([[:a, 1], [:b, 2]]).should == :a
27
+ util.weighted_random([[:a, 1], [:b, 2]]).should == :b
28
+ util.weighted_random([[:a, 1], [:b, 2]]).should == :b
29
+ end
30
+
31
+ it "should return nil when there are no elements" do
32
+ VSphereCloud::Resources::Util.weighted_random([]).should be_nil
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,216 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../../../spec_helper", __FILE__)
4
+
5
+ describe VSphereCloud::Resources do
6
+
7
+ describe :datacenters do
8
+ it "should fetch the datacenters the first time" do
9
+ vcenter_config = mock(:vcenter_config)
10
+ VSphereCloud::Config.vcenter = vcenter_config
11
+ dc_config = mock(:dc_config)
12
+ dc_config.stub(:name).and_return("foo")
13
+ vcenter_config.stub(:datacenters).and_return({"foo" => dc_config})
14
+ dc = mock(:dc)
15
+ VSphereCloud::Resources::Datacenter.should_receive(:new).with(dc_config).
16
+ once.and_return(dc)
17
+
18
+ resources = VSphereCloud::Resources.new
19
+ resources.datacenters.should == {"foo" => dc}
20
+ end
21
+
22
+ it "should use cached datacenters" do
23
+ vcenter_config = mock(:vcenter_config)
24
+ VSphereCloud::Config.vcenter = vcenter_config
25
+ dc_config = mock(:dc_config)
26
+ dc_config.stub(:name).and_return("foo")
27
+ vcenter_config.stub(:datacenters).and_return({"foo" => dc_config})
28
+ dc = mock(:dc)
29
+ VSphereCloud::Resources::Datacenter.should_receive(:new).with(dc_config).
30
+ once.and_return(dc)
31
+
32
+ resources = VSphereCloud::Resources.new
33
+ resources.datacenters.should == {"foo" => dc}
34
+ resources.datacenters.should == {"foo" => dc}
35
+ end
36
+
37
+ it "should flush stale cached datacenters" do
38
+ vcenter_config = mock(:vcenter_config)
39
+ VSphereCloud::Config.vcenter = vcenter_config
40
+ dc_config = mock(:dc_config)
41
+ dc_config.stub(:name).and_return("foo")
42
+ vcenter_config.stub(:datacenters).and_return({"foo" => dc_config})
43
+ dc = mock(:dc)
44
+ VSphereCloud::Resources::Datacenter.should_receive(:new).with(dc_config).
45
+ twice.and_return(dc)
46
+
47
+ now = Time.now.to_i
48
+ Time.should_receive(:now).and_return(now, now, now + 120, now + 120)
49
+
50
+ resources = VSphereCloud::Resources.new
51
+ resources.datacenters.should == {"foo" => dc}
52
+ resources.datacenters.should == {"foo" => dc}
53
+ end
54
+ end
55
+
56
+ describe :persistent_datastore do
57
+ it "should return the persistent datastore" do
58
+ dc = mock(:dc)
59
+ cluster = mock(:cluster)
60
+ dc.stub(:clusters).and_return({"bar" => cluster})
61
+ datastore = mock(:datastore)
62
+ cluster.stub(:persistent).with("baz").and_return(datastore)
63
+ resources = VSphereCloud::Resources.new
64
+ resources.stub(:datacenters).and_return({"foo" => dc})
65
+ resources.persistent_datastore("foo", "bar", "baz").should == datastore
66
+ resources.persistent_datastore("foo", "ba", "baz").should be_nil
67
+ end
68
+ end
69
+
70
+ describe :validate_persistent_datastore do
71
+ it "should return true if the provided datastore is still persistent" do
72
+ dc = mock(:dc)
73
+ cluster = mock(:cluster)
74
+ dc.stub(:clusters).and_return({"bar" => cluster})
75
+ datastore = mock(:datastore)
76
+ cluster.stub(:persistent).with("baz").and_return(datastore)
77
+ resources = VSphereCloud::Resources.new
78
+ resources.stub(:datacenters).and_return({"foo" => dc})
79
+ resources.validate_persistent_datastore("foo", "baz").should be_true
80
+ end
81
+
82
+ it "should return false if the provided datastore is not persistent" do
83
+ dc = mock(:dc)
84
+ cluster = mock(:cluster)
85
+ dc.stub(:clusters).and_return({"bar" => cluster})
86
+ cluster.stub(:persistent).with("baz").and_return(nil)
87
+ resources = VSphereCloud::Resources.new
88
+ resources.stub(:datacenters).and_return({"foo" => dc})
89
+ resources.validate_persistent_datastore("foo", "baz").should be_false
90
+ end
91
+ end
92
+
93
+ describe :place_persistent_datastore do
94
+ it "should return the datastore when it was placed successfully" do
95
+ dc = mock(:dc)
96
+ cluster = mock(:cluster)
97
+ dc.stub(:clusters).and_return({"bar" => cluster})
98
+ datastore = mock(:datastore)
99
+ datastore.should_receive(:allocate).with(1024)
100
+ cluster.should_receive(:pick_persistent).with(1024).and_return(datastore)
101
+ resources = VSphereCloud::Resources.new
102
+ resources.stub(:datacenters).and_return({"foo" => dc})
103
+ resources.place_persistent_datastore("foo", "bar", 1024).
104
+ should == datastore
105
+ end
106
+
107
+ it "should return nil when it wasn't placed successfully" do
108
+ dc = mock(:dc)
109
+ cluster = mock(:cluster)
110
+ dc.stub(:clusters).and_return({"bar" => cluster})
111
+ cluster.should_receive(:pick_persistent).with(1024).and_return(nil)
112
+ resources = VSphereCloud::Resources.new
113
+ resources.stub(:datacenters).and_return({"foo" => dc})
114
+ resources.place_persistent_datastore("foo", "bar", 1024).
115
+ should be_nil
116
+ end
117
+ end
118
+
119
+ describe :place do
120
+ it "should allocate memory and ephemeral disk space" do
121
+ dc = mock(:dc)
122
+ cluster = mock(:cluster)
123
+ dc.stub(:clusters).and_return({"bar" => cluster})
124
+ datastore = mock(:datastore)
125
+ cluster.stub(:name).and_return("bar")
126
+ cluster.stub(:persistent).with("baz").and_return(datastore)
127
+ resources = VSphereCloud::Resources.new
128
+ resources.stub(:datacenters).and_return({"foo" => dc})
129
+
130
+ scorer = mock(:scorer)
131
+ scorer.should_receive(:score).and_return(4)
132
+ VSphereCloud::Resources::Scorer.should_receive(:new).
133
+ with(cluster, 512, 1024, []).and_return(scorer)
134
+
135
+ cluster.should_receive(:allocate).with(512)
136
+ cluster.should_receive(:pick_ephemeral).with(1024).and_return(datastore)
137
+ datastore.should_receive(:allocate).with(1024)
138
+
139
+ resources.place(512, 1024, []).should == [cluster, datastore]
140
+ end
141
+
142
+ it "should prioritize persistent locality" do
143
+ dc = mock(:dc)
144
+ cluster_a = mock(:cluster_a)
145
+ cluster_b = mock(:cluster_b)
146
+ dc.stub(:clusters).and_return({"a" => cluster_a, "b" => cluster_b})
147
+
148
+ datastore_a = mock(:datastore_a)
149
+ cluster_a.stub(:name).and_return("ds_a")
150
+ cluster_a.stub(:persistent).with("ds_a").and_return(datastore_a)
151
+ cluster_a.stub(:persistent).with("ds_b").and_return(nil)
152
+
153
+ datastore_b = mock(:datastore_b)
154
+ cluster_b.stub(:name).and_return("ds_b")
155
+ cluster_b.stub(:persistent).with("ds_a").and_return(nil)
156
+ cluster_b.stub(:persistent).with("ds_b").and_return(datastore_b)
157
+
158
+ resources = VSphereCloud::Resources.new
159
+ resources.stub(:datacenters).and_return({"foo" => dc})
160
+
161
+ scorer_b = mock(:scorer_a)
162
+ scorer_b.should_receive(:score).and_return(4)
163
+ VSphereCloud::Resources::Scorer.should_receive(:new).
164
+ with(cluster_b, 512, 1024, [2048]).and_return(scorer_b)
165
+
166
+ cluster_b.should_receive(:allocate).with(512)
167
+ cluster_b.should_receive(:pick_ephemeral).with(1024).
168
+ and_return(datastore_b)
169
+ datastore_b.should_receive(:allocate).with(1024)
170
+
171
+ resources.place(512, 1024,
172
+ [{:size => 2048, :dc_name => "foo", :ds_name => "ds_a"},
173
+ {:size => 4096, :dc_name => "foo", :ds_name => "ds_b"}]).
174
+ should == [cluster_b, datastore_b]
175
+ end
176
+
177
+ it "should ignore locality when there is no space" do
178
+ dc = mock(:dc)
179
+ cluster_a = mock(:cluster_a)
180
+ cluster_b = mock(:cluster_b)
181
+ dc.stub(:clusters).and_return({"a" => cluster_a, "b" => cluster_b})
182
+
183
+ datastore_a = mock(:datastore_a)
184
+ cluster_a.stub(:name).and_return("ds_a")
185
+ cluster_a.stub(:persistent).with("ds_a").and_return(datastore_a)
186
+ cluster_a.stub(:persistent).with("ds_b").and_return(nil)
187
+
188
+ datastore_b = mock(:datastore_b)
189
+ cluster_b.stub(:name).and_return("ds_b")
190
+ cluster_b.stub(:persistent).with("ds_a").and_return(nil)
191
+ cluster_b.stub(:persistent).with("ds_b").and_return(datastore_b)
192
+
193
+ resources = VSphereCloud::Resources.new
194
+ resources.stub(:datacenters).and_return({"foo" => dc})
195
+
196
+ scorer_a = mock(:scorer_a)
197
+ scorer_a.should_receive(:score).twice.and_return(0)
198
+ VSphereCloud::Resources::Scorer.should_receive(:new).
199
+ with(cluster_a, 512, 1024, []).twice.and_return(scorer_a)
200
+
201
+ scorer_b = mock(:scorer_b)
202
+ scorer_b.should_receive(:score).and_return(4)
203
+ VSphereCloud::Resources::Scorer.should_receive(:new).
204
+ with(cluster_b, 512, 1024, [2048]).and_return(scorer_b)
205
+
206
+ cluster_b.should_receive(:allocate).with(512)
207
+ cluster_b.should_receive(:pick_ephemeral).with(1024).
208
+ and_return(datastore_b)
209
+ datastore_b.should_receive(:allocate).with(1024)
210
+
211
+ resources.place(512, 1024,
212
+ [{:size => 2048, :dc_name => "foo", :ds_name => "ds_a"}]).
213
+ should == [cluster_b, datastore_b]
214
+ end
215
+ end
216
+ end