foreman_google 3.0.8 → 3.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 260fb1ec541eb5194c170880e719331430974ae4fe2da542b5bc4ca37c339d71
4
- data.tar.gz: eb66f283bbfd1dba34a92828eab38bdd000d1c44ee8de6ac92eaaf91d2032268
3
+ metadata.gz: 6532064006813fbb57a5c62073d7f84f19fac3ae73899edf1e30b1f36d369f7b
4
+ data.tar.gz: 83449fb14ba738ad769c81f813effccf1bbceb79b7eeda2904ddca8c3fd6269f
5
5
  SHA512:
6
- metadata.gz: b1de4d2c31804d55fa4fb2345950e4c8047788dbbf4c9fcca952500e06343eebfb465badda65472315e9de7527b3337fb7b7b603477c2517e324ea112fdb6675
7
- data.tar.gz: 593f32a9267b4096dcb928fb10d3ac875f61bbb720b807bcc7d8c4c4009865afbe8ebe373de39ebfefdbbfb3873dcc18ce836c4c7dade93d5042e2aecf3a51aa
6
+ metadata.gz: 761b6101972b2d261daf7726c8ec8da2465909831a3bfa3d6de52ac1bae5a8a620ee8eef30728bebadd2a366111ce82e6f1989ae92a995e9cdf4045c61011bfd
7
+ data.tar.gz: 0244b37a972bae1d9a647f1949d11fb08cdf12bec291e8f69ff2d31ea6596319b355851b384331b9cce64d398cd3e6220ef85629f3e013ba33cd03fb9e13c4a9
@@ -29,12 +29,14 @@ module GoogleCloudCompute
29
29
  end
30
30
 
31
31
  def for_instance(instance)
32
+ first_nic = instance.network_interfaces[0]
33
+
32
34
  {
33
35
  name: instance.name, hostname: instance.name,
34
36
  creation_timestamp: instance.creation_timestamp.to_datetime,
35
37
  zone_name: instance.zone.split('/').last,
36
38
  machine_type: instance.machine_type,
37
- network: instance.network_interfaces[0].network.split('/').last,
39
+ network: first_nic&.network&.split('/')&.last,
38
40
  network_interfaces: instance.network_interfaces,
39
41
  volumes: instance.disks, metadata: instance.metadata
40
42
  }
@@ -96,10 +96,8 @@ module ForemanGoogle
96
96
  end
97
97
 
98
98
  def setup_key_pair
99
- require 'sshkey'
100
-
101
- key = ::SSHKey.generate
102
- build_key_pair name: "foreman-#{id}#{Foreman.uuid}", secret: key.private_key, public: key.ssh_public_key
99
+ key_pair = Foreman::Provision::SshKey.generate
100
+ build_key_pair name: "foreman-#{id}#{Foreman.uuid}", secret: key_pair.private_key, public: key_pair.public_key
103
101
  end
104
102
 
105
103
  def self.provider_friendly_name
@@ -35,12 +35,12 @@ module ForemanGoogle
35
35
  alias_method :state, :status
36
36
 
37
37
  def start
38
- raise Foreman::Exception('unable to start machine that is not persisted') unless persisted?
38
+ raise Foreman::Exception, N_('unable to start machine that is not persisted') unless persisted?
39
39
  @client.start(@zone, identity)
40
40
  end
41
41
 
42
42
  def stop
43
- raise Foreman::Exception('unable to stop machine that is not persisted') unless persisted?
43
+ raise Foreman::Exception, N_('unable to stop machine that is not persisted') unless persisted?
44
44
  @client.stop(@zone, identity)
45
45
  end
46
46
 
@@ -18,7 +18,7 @@ module ForemanGoogle
18
18
 
19
19
  initializer 'foreman_google.register_plugin', before: :finisher_hook do |_app|
20
20
  Foreman::Plugin.register :foreman_google do
21
- requires_foreman '>= 3.13.0'
21
+ requires_foreman '>= 5.1'
22
22
  register_global_js_file 'global'
23
23
  register_gettext
24
24
 
@@ -1,3 +1,3 @@
1
1
  module ForemanGoogle
2
- VERSION = '3.0.8'.freeze
2
+ VERSION = '3.1.0'.freeze
3
3
  end
@@ -0,0 +1,71 @@
1
+ require 'test_google_helper'
2
+
3
+ module ForemanGoogle
4
+ module Api
5
+ module V2
6
+ class ComputeResourcesExtensionsTest < GoogleTestCase
7
+ describe 'the real API controller integration' do
8
+ it 'loads the Google parameter extension into the compute resource controller' do
9
+ assert_includes ::Api::V2::ComputeResourcesController.ancestors,
10
+ ::Foreman::Controller::Parameters::ComputeResourceExtension
11
+ end
12
+
13
+ it 'permits Google compute resource parameters' do
14
+ context = ::Api::V2::ComputeResourcesController.parameter_filter_context
15
+ params = ActionController::Parameters.new(
16
+ compute_resource: { key_path: '/tmp/key.json', zone: 'us-east1-b' }
17
+ )
18
+
19
+ filtered = ::Api::V2::ComputeResourcesController
20
+ .compute_resource_params_filter
21
+ .filter_params(params, context)
22
+
23
+ assert_equal({ 'key_path' => '/tmp/key.json', 'zone' => 'us-east1-b' }, filtered.to_h)
24
+ end
25
+ end
26
+
27
+ let(:controller_class) do
28
+ Class.new do
29
+ def self.before_action(*)
30
+ end
31
+
32
+ include ForemanGoogle::Api::V2::ComputeResourcesExtensions
33
+
34
+ attr_accessor :params
35
+
36
+ def compute_resource_params
37
+ params[:compute_resource]
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#read_key' do
43
+ it 'reads key file content into password for GCE provider' do
44
+ key_content = '{"type": "service_account", "project_id": "test"}'
45
+
46
+ Tempfile.open('gce_key') do |f|
47
+ f.write(key_content)
48
+ f.flush
49
+
50
+ ctrl = controller_class.new
51
+ ctrl.params = { 'compute_resource' => { 'provider' => 'GCE', 'key_path' => f.path } }.with_indifferent_access
52
+ ctrl.send(:read_key)
53
+
54
+ assert_equal key_content, ctrl.params[:compute_resource][:password]
55
+ assert_not ctrl.params[:compute_resource].key?('key_path')
56
+ end
57
+ end
58
+
59
+ it 'skips when provider is not GCE' do
60
+ ctrl = controller_class.new
61
+ ctrl.params = { 'compute_resource' => { 'provider' => 'EC2', 'key_path' => '/nonexistent' } }.with_indifferent_access
62
+ ctrl.send(:read_key)
63
+
64
+ assert_nil ctrl.params[:compute_resource][:password]
65
+ assert_equal '/nonexistent', ctrl.params[:compute_resource]['key_path']
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_google_helper'
2
+
3
+ module ForemanGoogle
4
+ class HostManagedExtensionsTest < GoogleTestCase
5
+ let(:host_class) do
6
+ Class.new do
7
+ include ForemanGoogle::HostManagedExtensions
8
+ attr_accessor :vm
9
+ end
10
+ end
11
+
12
+ describe '#ip_addresses' do
13
+ it 'returns vm ip_addresses when vm exists' do
14
+ vm = mock('GoogleCompute')
15
+ vm.expects(:ip_addresses).returns(['1.2.3.4', '10.0.0.1'])
16
+
17
+ host = host_class.new
18
+ host.vm = vm
19
+ assert_equal ['1.2.3.4', '10.0.0.1'], host.ip_addresses
20
+ end
21
+
22
+ it 'returns empty array when vm is nil' do
23
+ host = host_class.new
24
+ host.vm = nil
25
+ assert_empty host.ip_addresses
26
+ end
27
+ end
28
+
29
+ describe '#vm_ip_address' do
30
+ it 'returns vm public IP when vm exists' do
31
+ vm = mock('GoogleCompute')
32
+ vm.expects(:vm_ip_address).returns('1.2.3.4')
33
+
34
+ host = host_class.new
35
+ host.vm = vm
36
+ assert_equal '1.2.3.4', host.vm_ip_address
37
+ end
38
+
39
+ it 'returns nil when vm is nil' do
40
+ host = host_class.new
41
+ host.vm = nil
42
+ assert_nil host.vm_ip_address
43
+ end
44
+ end
45
+ end
46
+ end
@@ -2,7 +2,7 @@ require 'test_google_helper'
2
2
 
3
3
  module ForemanGoogle
4
4
  class GCETest < GoogleTestCase
5
- subject { ForemanGoogle::GCE.new(zone: 'zone', password: gauth_json) }
5
+ subject { ForemanGoogle::GCE.new(zone: 'us-east1-b', password: gauth_json) }
6
6
  let(:service) { mock('GoogleAdapter') }
7
7
 
8
8
  let(:instance_args) do
@@ -18,6 +18,142 @@ module ForemanGoogle
18
18
  service.stubs(:project_id).returns('project_id')
19
19
  end
20
20
 
21
+ describe '#to_label' do
22
+ it 'includes name, zone, and provider' do
23
+ subject.name = 'my-gce'
24
+ expected = 'my-gce (us-east1-b-Google)'
25
+ assert_equal expected, subject.to_label
26
+ end
27
+ end
28
+
29
+ describe '#capabilities' do
30
+ it 'returns image and new_volume' do
31
+ assert_equal %i[image new_volume], subject.capabilities
32
+ end
33
+ end
34
+
35
+ describe '#provided_attributes' do
36
+ it 'includes ip mapped to vm_ip_address' do
37
+ attrs = subject.provided_attributes
38
+ assert_equal :vm_ip_address, attrs[:ip]
39
+ end
40
+ end
41
+
42
+ describe '#user_data_supported?' do
43
+ it 'returns true' do
44
+ assert subject.user_data_supported?
45
+ end
46
+ end
47
+
48
+ describe '#zone' do
49
+ it 'reads from url attribute' do
50
+ subject.url = 'us-central1-a'
51
+ assert_equal 'us-central1-a', subject.zone
52
+ end
53
+ end
54
+
55
+ describe '#zone=' do
56
+ it 'writes to url attribute' do
57
+ subject.zone = 'europe-west1-b'
58
+ assert_equal 'europe-west1-b', subject.url
59
+ end
60
+ end
61
+
62
+ describe 'validations' do
63
+ it 'is valid with name, zone, and password' do
64
+ subject.name = 'test-gce'
65
+ assert subject.valid?, "Expected subject to be valid, got errors: #{subject.errors.full_messages}"
66
+ end
67
+
68
+ it 'requires password' do
69
+ cr = ForemanGoogle::GCE.new(zone: 'us-east1-b', password: nil)
70
+ assert_not cr.valid?
71
+ assert_includes cr.errors.attribute_names, :password
72
+ end
73
+
74
+ it 'requires zone' do
75
+ cr = ForemanGoogle::GCE.new(zone: nil, password: gauth_json)
76
+ assert_not cr.valid?
77
+ assert_includes cr.errors.attribute_names, :zone
78
+ end
79
+
80
+ it 'requires name' do
81
+ cr = ForemanGoogle::GCE.new(name: nil, zone: 'us-east1-b', password: gauth_json)
82
+ assert_not cr.valid?
83
+ assert_includes cr.errors.attribute_names, :name
84
+ end
85
+ end
86
+
87
+ describe '#zones' do
88
+ it 'returns zone names from client' do
89
+ zones = [OpenStruct.new(name: 'us-east1-b'), OpenStruct.new(name: 'us-west1-a')]
90
+ service.expects(:zones).returns(zones)
91
+ assert_equal %w[us-east1-b us-west1-a], subject.zones
92
+ end
93
+
94
+ it 'is aliased as available_zones' do
95
+ zones = [OpenStruct.new(name: 'us-east1-b')]
96
+ service.expects(:zones).returns(zones)
97
+ assert_equal %w[us-east1-b], subject.available_zones
98
+ end
99
+ end
100
+
101
+ describe '#networks' do
102
+ it 'returns network names from client' do
103
+ networks = [OpenStruct.new(name: 'default'), OpenStruct.new(name: 'custom')]
104
+ service.expects(:networks).returns(networks)
105
+ assert_equal %w[default custom], subject.networks
106
+ end
107
+ end
108
+
109
+ describe '#available_networks' do
110
+ it 'returns full network objects from client' do
111
+ network_objects = [OpenStruct.new(name: 'default')]
112
+ service.expects(:networks).returns(network_objects)
113
+ assert_equal network_objects, subject.available_networks
114
+ end
115
+ end
116
+
117
+ describe '#machine_types' do
118
+ it 'returns machine types for the zone from client' do
119
+ types = [OpenStruct.new(name: 'e2-micro')]
120
+ service.expects(:machine_types).with('us-east1-b').returns(types)
121
+ assert_equal types, subject.machine_types
122
+ end
123
+
124
+ it 'is aliased as available_flavors' do
125
+ types = [OpenStruct.new(name: 'n1-standard-1')]
126
+ service.expects(:machine_types).with('us-east1-b').returns(types)
127
+ assert_equal types, subject.available_flavors
128
+ end
129
+ end
130
+
131
+ describe '#available_images' do
132
+ it 'delegates to client.images with filter' do
133
+ images = [OpenStruct.new(name: 'centos-7')]
134
+ service.expects(:images).with(filter: nil).returns(images)
135
+ assert_equal images, subject.available_images
136
+ end
137
+
138
+ it 'passes custom filter to client' do
139
+ images = [OpenStruct.new(name: 'centos-7')]
140
+ service.expects(:images).with(filter: 'name = "centos"').returns(images)
141
+ assert_equal images, subject.available_images(filter: 'name = "centos"')
142
+ end
143
+ end
144
+
145
+ describe '#filter_for_images' do
146
+ it 'defaults to nil' do
147
+ assert_nil subject.filter_for_images
148
+ end
149
+ end
150
+
151
+ describe '#google_project_id' do
152
+ it 'delegates to client' do
153
+ assert_equal 'project_id', subject.google_project_id
154
+ end
155
+ end
156
+
21
157
  describe '#find_vm_by_uuid' do
22
158
  it 'does query gce' do
23
159
  instance = OpenStruct.new(**instance_args)
@@ -48,11 +184,29 @@ module ForemanGoogle
48
184
  end
49
185
 
50
186
  it 'iteration over the vms array' do
51
- subject.vms.each_with_index { |instance, i| assert instance.name, instances[i].name }
187
+ subject.vms.each_with_index { |instance, i| assert_equal instances[i].name, instance.name }
52
188
  end
53
189
 
54
190
  it 'all method' do
55
- subject.vms.all.each_with_index { |instance, i| assert instance.name, instances[i].name }
191
+ subject.vms.all.each_with_index { |instance, i| assert_equal instances[i].name, instance.name }
192
+ end
193
+ end
194
+
195
+ describe '#new_vm' do
196
+ it 'assigns provided attributes' do
197
+ vm = subject.new_vm(name: 'test-vm', machine_type: 'e2-micro')
198
+ assert_equal 'test-vm', vm.name
199
+ assert_equal 'e2-micro', vm.machine_type
200
+ end
201
+
202
+ it 'converts volumes_attributes nested hash' do
203
+ attrs = {
204
+ 'name' => 'test-vm',
205
+ 'volumes_attributes' => { '0' => { 'size_gb' => '20' } },
206
+ }
207
+ vm = subject.new_vm(attrs)
208
+ assert_equal 1, vm.volumes.size
209
+ assert_equal 20, vm.volumes.first.size_gb
56
210
  end
57
211
  end
58
212
 
@@ -65,5 +219,123 @@ module ForemanGoogle
65
219
  value { subject.create_vm({ image_id: 0 }) }.must_raise(::Foreman::Exception)
66
220
  end
67
221
  end
222
+
223
+ describe '#create_vm success path' do
224
+ let(:os_image) { OpenStruct.new(username: 'gce_user', name: 'centos-7') }
225
+ let(:gce_image) { OpenStruct.new(id: 42, self_link: 'image-link') }
226
+ let(:key_pair_obj) { OpenStruct.new(public: 'ssh-rsa AAAA') }
227
+ let(:vm) { mock('GoogleCompute') }
228
+
229
+ setup do
230
+ service.stubs(:image).returns(gce_image)
231
+ service.stubs(:instance)
232
+ subject.stubs(:images).returns(stub(find_by: os_image))
233
+ subject.stubs(:key_pair).returns(key_pair_obj)
234
+ subject.stubs(:new_vm).returns(vm)
235
+ vm.stubs(:hostname).returns('test-vm')
236
+
237
+ vm.expects(:create_volumes)
238
+ vm.expects(:create_instance)
239
+ vm.expects(:set_disk_auto_delete)
240
+ end
241
+
242
+ it 'creates volumes, instance, and sets auto-delete' do
243
+ result = subject.create_vm({ image_id: 42 })
244
+ assert_kind_of ForemanGoogle::GoogleCompute, result
245
+ end
246
+ end
247
+
248
+ describe '#create_vm rollback on error' do
249
+ let(:os_image) { OpenStruct.new(username: 'gce_user', name: 'centos-7') }
250
+ let(:gce_image) { OpenStruct.new(id: 42, self_link: 'image-link') }
251
+ let(:key_pair_obj) { OpenStruct.new(public: 'ssh-rsa AAAA') }
252
+ let(:vm) { mock('GoogleCompute') }
253
+
254
+ setup do
255
+ subject.stubs(:images).returns(stub(find_by: os_image))
256
+ service.stubs(:image).returns(gce_image)
257
+ subject.stubs(:key_pair).returns(key_pair_obj)
258
+ subject.stubs(:new_vm).returns(vm)
259
+ vm.stubs(:create_volumes).raises(::Google::Cloud::Error.new('quota exceeded'))
260
+
261
+ vm.expects(:destroy_volumes)
262
+ end
263
+
264
+ it 'destroys volumes and raises WrappedException' do
265
+ assert_raises(Foreman::WrappedException) { subject.create_vm({ image_id: 42 }) }
266
+ end
267
+ end
268
+
269
+ describe '#destroy_vm' do
270
+ it 'calls set_disk_auto_delete and delete_instance' do
271
+ service.expects(:set_disk_auto_delete).with('us-east1-b', 'vm-uuid')
272
+ service.expects(:delete_instance).with('us-east1-b', 'vm-uuid')
273
+ subject.destroy_vm('vm-uuid')
274
+ end
275
+
276
+ it 'returns true when VM not found' do
277
+ service.expects(:set_disk_auto_delete).raises(ActiveRecord::RecordNotFound)
278
+ assert subject.destroy_vm('missing-vm')
279
+ end
280
+ end
281
+
282
+ describe '#new_volume' do
283
+ it 'returns an AttachedDisk with 20 GB default' do
284
+ vol = subject.new_volume
285
+ assert_kind_of Google::Cloud::Compute::V1::AttachedDisk, vol
286
+ assert_equal 20, vol.disk_size_gb
287
+ end
288
+
289
+ it 'merges provided attributes' do
290
+ vol = subject.new_volume(device_name: 'boot-disk')
291
+ assert_equal 'boot-disk', vol.device_name
292
+ assert_equal 20, vol.disk_size_gb
293
+ end
294
+ end
295
+
296
+ describe '#console' do
297
+ let(:vm) { mock('GoogleCompute') }
298
+
299
+ setup do
300
+ subject.stubs(:find_vm_by_uuid).returns(vm)
301
+ end
302
+
303
+ it 'returns serial output when VM is ready' do
304
+ vm.stubs(:ready?).returns(true)
305
+ vm.stubs(:serial_port_output).returns('boot log...')
306
+ vm.stubs(:name).returns('test-vm')
307
+
308
+ result = subject.console('test-vm')
309
+ assert_equal 'boot log...', result['output']
310
+ assert_equal 'log', result[:type]
311
+ assert_equal 'test-vm', result[:name]
312
+ assert result['timestamp'].is_a?(Time)
313
+ end
314
+
315
+ it 'raises when VM is not ready' do
316
+ vm.stubs(:ready?).returns(false)
317
+ assert_raises(::Foreman::Exception) { subject.console('test-vm') }
318
+ end
319
+ end
320
+
321
+ describe '#associated_host' do
322
+ it 'calls associate_by with ip addresses' do
323
+ vm = OpenStruct.new(public_ip_address: '1.2.3.4', private_ip_address: '10.0.0.1')
324
+ subject.expects(:associate_by).with('ip', ['1.2.3.4', '10.0.0.1'])
325
+ subject.associated_host(vm)
326
+ end
327
+ end
328
+
329
+ describe '#vm_ready' do
330
+ it 'polls until vm is ready' do
331
+ vm = mock('GoogleCompute')
332
+ vm.stubs(:reload).returns(vm)
333
+ vm.stubs(:ready?).returns(false, true)
334
+ vm.stubs(:wait_for).yields.returns({ duration: 2 })
335
+
336
+ result = subject.vm_ready(vm)
337
+ assert_equal({ duration: 2 }, result)
338
+ end
339
+ end
68
340
  end
69
341
  end
@@ -194,20 +194,209 @@ module ForemanGoogle
194
194
 
195
195
  it '@network' do
196
196
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
197
- assert cr.network, 'default'
197
+ assert_equal 'default', cr.network
198
198
 
199
199
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { network: 'my-network' })
200
- assert cr.network, 'my-network'
200
+ assert_equal 'my-network', cr.network
201
201
  end
202
202
 
203
203
  it '@zone' do
204
204
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
205
- assert zone, cr.zone
205
+ assert_equal zone, cr.zone
206
206
  end
207
207
 
208
208
  it '@zone_name' do
209
209
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
210
- assert zone, cr.zone_name
210
+ assert_equal zone, cr.zone_name
211
+ end
212
+
213
+ describe '#status' do
214
+ it 'returns status when persisted' do
215
+ instance.status = 'RUNNING'
216
+ client.expects(:instance).with(zone, identity).returns(instance)
217
+ assert_equal 'RUNNING', subject.status
218
+ end
219
+
220
+ it 'returns false when not persisted' do
221
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
222
+ assert_not cr.status
223
+ end
224
+ end
225
+
226
+ describe '#state' do
227
+ it 'is an alias for status' do
228
+ instance.status = 'TERMINATED'
229
+ client.expects(:instance).with(zone, identity).returns(instance)
230
+ assert_equal subject.status, subject.state
231
+ end
232
+ end
233
+
234
+ describe '#start' do
235
+ it 'delegates to client.start when persisted' do
236
+ client.stubs(:instance).with(zone, identity).returns(instance)
237
+ client.expects(:start).with(zone, identity).returns(true)
238
+ subject.start
239
+ end
240
+
241
+ it 'raises when not persisted' do
242
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
243
+ assert_raises(Foreman::Exception) { cr.start }
244
+ end
245
+ end
246
+
247
+ describe '#stop' do
248
+ it 'delegates to client.stop when persisted' do
249
+ client.stubs(:instance).with(zone, identity).returns(instance)
250
+ client.expects(:stop).with(zone, identity).returns(true)
251
+ subject.stop
252
+ end
253
+
254
+ it 'raises when not persisted' do
255
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
256
+ assert_raises(Foreman::Exception) { cr.stop }
257
+ end
258
+ end
259
+
260
+ describe '#to_s' do
261
+ it 'returns the name' do
262
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { name: 'my-vm' })
263
+ assert_equal 'my-vm', cr.to_s
264
+ end
265
+ end
266
+
267
+ describe '#interfaces' do
268
+ it 'returns network_interfaces' do
269
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
270
+ assert_equal cr.network_interfaces, cr.interfaces
271
+ end
272
+ end
273
+
274
+ describe '#vm_description' do
275
+ it 'delegates to pretty_machine_type' do
276
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
277
+ assert_equal cr.pretty_machine_type, cr.vm_description
278
+ end
279
+ end
280
+
281
+ describe '#vm_ip_address - no network interfaces' do
282
+ it 'returns nil' do
283
+ empty_instance = OpenStruct.new(
284
+ name: 'instance', network_interfaces: [],
285
+ creation_timestamp: Time.zone.now, zone: zone,
286
+ machine_type: 'machineTypes/e2-micro'
287
+ )
288
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: empty_instance)
289
+ assert_nil cr.vm_ip_address
290
+ end
291
+ end
292
+
293
+ describe '#private_ip_address - no network interfaces' do
294
+ it 'returns nil' do
295
+ empty_instance = OpenStruct.new(
296
+ name: 'instance', network_interfaces: [],
297
+ creation_timestamp: Time.zone.now, zone: zone,
298
+ machine_type: 'machineTypes/e2-micro'
299
+ )
300
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: empty_instance)
301
+ assert_nil cr.private_ip_address
302
+ end
303
+ end
304
+
305
+ describe '#pretty_image_name - no disks' do
306
+ it 'returns nil' do
307
+ instance.disks = []
308
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
309
+ assert_nil cr.pretty_image_name
310
+ end
311
+ end
312
+
313
+ describe '#ip_addresses' do
314
+ it 'returns public and private IP' do
315
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
316
+ assert_equal ['1.2.3.4', '10.10.10.23'], cr.ip_addresses
317
+ end
318
+ end
319
+
320
+ describe '#serial_port_output' do
321
+ it 'delegates to client' do
322
+ client.stubs(:instance).with(zone, identity).returns(instance)
323
+ client.expects(:serial_port_output).with(zone, identity).returns(OpenStruct.new(contents: 'boot log'))
324
+ assert_equal 'boot log', subject.serial_port_output
325
+ end
326
+
327
+ it 'returns nil when client returns nil' do
328
+ client.stubs(:instance).with(zone, identity).returns(instance)
329
+ client.expects(:serial_port_output).with(zone, identity).returns(nil)
330
+ assert_nil subject.serial_port_output
331
+ end
332
+ end
333
+
334
+ describe '#volumes_attributes=' do
335
+ it 'is a no-op' do
336
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
337
+ cr.volumes_attributes = { '0' => { size_gb: 10 } }
338
+ assert cr.volumes.any?
339
+ end
340
+ end
341
+
342
+ describe '#reload - without identity' do
343
+ it 'returns nil' do
344
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
345
+ assert_nil cr.reload
346
+ end
347
+ end
348
+
349
+ describe '#create_volumes' do
350
+ it 'inserts disks and waits for READY' do
351
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { volumes: [{ size_gb: '20' }] })
352
+
353
+ client.expects(:insert_disk).with(zone, cr.volumes.first.insert_attrs)
354
+ client.expects(:disk).with(zone, cr.volumes.first.device_name).returns(OpenStruct.new(status: 'READY'))
355
+ client.expects(:wait_for).yields.returns({ duration: 1 })
356
+
357
+ cr.create_volumes
358
+ end
359
+ end
360
+
361
+ describe '#destroy_volumes' do
362
+ it 'deletes each volume disk' do
363
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { volumes: [{ size_gb: '20' }] })
364
+ client.expects(:delete_disk).with(zone, cr.volumes.first.device_name)
365
+ cr.destroy_volumes
366
+ end
367
+ end
368
+
369
+ describe '#create_instance' do
370
+ it 'calls insert_instance via ComputeAttributes' do
371
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { name: 'test-vm', machine_type: 'e2-micro' })
372
+ client.expects(:insert_instance).with(zone, has_key(:name))
373
+ cr.create_instance
374
+ end
375
+ end
376
+
377
+ describe '#set_disk_auto_delete' do
378
+ it 'delegates to client' do
379
+ args = { name: 'my-vm' }
380
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: args)
381
+ client.expects(:set_disk_auto_delete).with(zone, 'my-vm')
382
+ cr.set_disk_auto_delete
383
+ end
384
+ end
385
+
386
+ describe '#wait_for' do
387
+ it 'delegates to client.wait_for' do
388
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
389
+ client.expects(:wait_for).yields.returns({ duration: 0 })
390
+ result = cr.wait_for { true }
391
+ assert_equal({ duration: 0 }, result)
392
+ end
393
+ end
394
+
395
+ describe '#public_ip_address' do
396
+ it 'is an alias for vm_ip_address' do
397
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
398
+ assert_equal cr.vm_ip_address, cr.public_ip_address
399
+ end
211
400
  end
212
401
  end
213
402
  end
@@ -131,7 +131,7 @@ module ForemanGoogle
131
131
 
132
132
  result = subject.insert_instance('us-east1-b', args)
133
133
 
134
- assert 'insert', result.operation.operation_type
134
+ assert_equal 'insert', result.operation.operation_type
135
135
  assert_includes result.operation.target_link, 'foreman-test-google'
136
136
  end
137
137
 
@@ -156,14 +156,14 @@ module ForemanGoogle
156
156
  stub_request(:post, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name/start')
157
157
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_start.json')))
158
158
  result = subject.start('us-east1-b', 'instance_name')
159
- assert 'start', result.operation.operation_type
159
+ assert_equal 'start', result.operation.operation_type
160
160
  end
161
161
 
162
162
  it '#stop' do
163
163
  stub_request(:post, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name/stop')
164
164
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_stop.json')))
165
165
  result = subject.stop('us-east1-b', 'instance_name')
166
- assert 'stop', result.operation.operation_type
166
+ assert_equal 'stop', result.operation.operation_type
167
167
  end
168
168
 
169
169
  it '#set_disk_auto_delete' do
@@ -174,7 +174,7 @@ module ForemanGoogle
174
174
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_set_disk_auto_delete.json')))
175
175
  result = subject.set_disk_auto_delete('us-east1-b', 'instance_name')
176
176
 
177
- assert 'device-1', result[0].source
177
+ assert_equal 'instance-1', result[0].device_name
178
178
  assert result[0].auto_delete
179
179
  end
180
180
  end
@@ -186,14 +186,14 @@ module ForemanGoogle
186
186
 
187
187
  result = subject.insert_disk('us-east1-b', { name: 'foreman-disk1', size_gb: 23 })
188
188
  assert_includes result.operation.target_link, 'foreman-disk1'
189
- assert 'insert', result.operation.operation_type
189
+ assert_equal 'insert', result.operation.operation_type
190
190
  end
191
191
 
192
192
  it '#get' do
193
193
  stub_request(:get, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/disks/foreman-disk1')
194
194
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'disks_get.json')))
195
195
  result = subject.disk('us-east1-b', 'foreman-disk1')
196
- assert 'foreman-disk1', result.name
196
+ assert_equal 'foreman-disk1', result.name
197
197
  end
198
198
 
199
199
  it '#delete' do
@@ -202,7 +202,59 @@ module ForemanGoogle
202
202
  result = subject.delete_disk('us-east1-b', 'foreman-disk1')
203
203
 
204
204
  assert_includes result.operation.target_link, 'foreman-disk1'
205
- assert 'delete', result.operation.operation_type
205
+ assert_equal 'delete', result.operation.operation_type
206
+ end
207
+ end
208
+
209
+ describe '#delete_instance' do
210
+ it 'deletes an instance' do
211
+ stub_request(:delete, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name')
212
+ .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_stop.json')))
213
+ result = subject.delete_instance('us-east1-b', 'instance_name')
214
+ assert_equal 'stop', result.operation.operation_type
215
+ end
216
+ end
217
+
218
+ describe '#image' do
219
+ setup do
220
+ stub_request(:get, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/global/images')
221
+ .to_return(body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'images_coastal.json')))
222
+ end
223
+
224
+ it 'finds image by numeric id' do
225
+ subject.stub(:all_projects, []) do
226
+ result = subject.image(1)
227
+ assert_equal 'coastal-image', result.name
228
+ end
229
+ end
230
+
231
+ it 'returns nil when image not found' do
232
+ subject.stub(:all_projects, []) do
233
+ assert_nil subject.image(999)
234
+ end
235
+ end
236
+ end
237
+
238
+ describe '#serial_port_output' do
239
+ it 'returns serial port output' do
240
+ body = { contents: 'boot log output', next: 12_345, start: 0, selfLink: 'self-link' }.to_json
241
+ stub_request(:get, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name/serialPort')
242
+ .to_return(status: 200, body: body)
243
+ result = subject.serial_port_output('us-east1-b', 'instance_name')
244
+ assert_equal 'boot log output', result.contents
245
+ end
246
+ end
247
+
248
+ describe '#project_id' do
249
+ it 'returns the project_id from auth JSON' do
250
+ assert_equal 'coastal-haven-123456', subject.project_id
251
+ end
252
+ end
253
+
254
+ describe '#wait_for' do
255
+ it 'returns immediately when block yields true' do
256
+ result = subject.wait_for { true }
257
+ assert result[:duration] <= 1
206
258
  end
207
259
  end
208
260
  end
@@ -0,0 +1,235 @@
1
+ require 'test_google_helper'
2
+
3
+ module GoogleCloudCompute
4
+ class ComputeAttributesTest < GoogleTestCase
5
+ let(:client) { mock('GoogleAdapter') }
6
+ subject { GoogleCloudCompute::ComputeAttributes.new(client) }
7
+
8
+ setup do
9
+ client.stubs(:project_id).returns('my-project')
10
+ end
11
+
12
+ describe '#for_new' do
13
+ describe 'name handling' do
14
+ it 'generates a default name with foreman- prefix when name is nil' do
15
+ result = subject.for_new({})
16
+ assert_match(/\Aforeman-\d+\z/, result[:name])
17
+ assert_equal result[:name], result[:hostname]
18
+ end
19
+
20
+ it 'parameterizes the provided name' do
21
+ result = subject.for_new(name: 'My VM Name')
22
+ assert_equal 'my-vm-name', result[:name]
23
+ assert_equal 'my-vm-name', result[:hostname]
24
+ end
25
+ end
26
+
27
+ describe 'network handling' do
28
+ it 'defaults to default network' do
29
+ result = subject.for_new({})
30
+ assert_equal 'default', result[:network]
31
+ end
32
+
33
+ it 'uses custom network name' do
34
+ result = subject.for_new(network: 'custom-net')
35
+ assert_equal 'custom-net', result[:network]
36
+ end
37
+
38
+ it 'builds full URL without external IP' do
39
+ result = subject.for_new(network: 'default')
40
+ expected_url = 'https://compute.googleapis.com/compute/v1/projects/my-project/global/networks/default'
41
+ assert_equal expected_url, result[:network_interfaces][0][:network]
42
+ end
43
+
44
+ it 'adds NAT access config with external IP' do
45
+ result = subject.for_new(associate_external_ip: '1')
46
+ nic = result[:network_interfaces][0]
47
+ assert_equal 'global/networks/default', nic[:network]
48
+ assert_equal [{ name: 'External NAT', type: 'ONE_TO_ONE_NAT' }], nic[:access_configs]
49
+ end
50
+
51
+ it 'uses custom network interfaces with external IP' do
52
+ result = subject.for_new(
53
+ associate_external_ip: '1',
54
+ network_interfaces: [{ network: 'global/networks/my-net' }]
55
+ )
56
+ nic = result[:network_interfaces][0]
57
+ assert_equal 'global/networks/my-net', nic[:network]
58
+ assert_equal [{ name: 'External NAT', type: 'ONE_TO_ONE_NAT' }], nic[:access_configs]
59
+ end
60
+ end
61
+
62
+ describe 'associate_external_ip boolean casting' do
63
+ it 'casts string 1 to true' do
64
+ result = subject.for_new(associate_external_ip: '1')
65
+ assert result[:associate_external_ip]
66
+ end
67
+
68
+ it 'casts string 0 to false' do
69
+ result = subject.for_new(associate_external_ip: '0')
70
+ assert_not result[:associate_external_ip]
71
+ end
72
+
73
+ it 'defaults to false when absent' do
74
+ result = subject.for_new({})
75
+ assert_not result[:associate_external_ip]
76
+ end
77
+ end
78
+
79
+ describe 'volume construction' do
80
+ it 'creates a default 20 GB disk when no volumes' do
81
+ result = subject.for_new({})
82
+ assert_equal 1, result[:volumes].length
83
+ assert_equal 20, result[:volumes].first.disk_size_gb
84
+ end
85
+
86
+ it 'creates volumes with custom size' do
87
+ result = subject.for_new(volumes: [{ size_gb: '50' }])
88
+ assert_equal 50, result[:volumes].first.disk_size_gb
89
+ end
90
+
91
+ it 'sets source image on first volume when image_id is provided' do
92
+ image = OpenStruct.new(id: 1, self_link: 'projects/my-project/global/images/centos-7')
93
+ client.stubs(:image).with(1).returns(image)
94
+
95
+ result = subject.for_new(
96
+ volumes: [{ size_gb: '20' }, { size_gb: '30' }],
97
+ image_id: '1'
98
+ )
99
+
100
+ assert_equal 'projects/my-project/global/images/centos-7', result[:volumes][0].source
101
+ assert_empty result[:volumes][1].source
102
+ end
103
+
104
+ it 'names disks sequentially' do
105
+ result = subject.for_new(name: 'test-vm', volumes: [{ size_gb: '20' }, { size_gb: '30' }])
106
+ assert_equal 'test-vm-disk1', result[:volumes][0].device_name
107
+ assert_equal 'test-vm-disk2', result[:volumes][1].device_name
108
+ end
109
+
110
+ it 'accepts disk_size_gb as an alternative key' do
111
+ result = subject.for_new(volumes: [{ disk_size_gb: '40' }])
112
+ assert_equal 40, result[:volumes].first.disk_size_gb
113
+ end
114
+ end
115
+
116
+ describe 'metadata construction' do
117
+ it 'includes ssh-keys' do
118
+ result = subject.for_new(username: 'gce_user', public_key: 'ssh-rsa AAAA')
119
+ ssh_item = result[:metadata][:items].find { |i| i[:key] == 'ssh-keys' }
120
+ assert_equal 'gce_user:ssh-rsa AAAA', ssh_item[:value]
121
+ end
122
+
123
+ it 'includes user-data when present' do
124
+ result = subject.for_new(username: 'user', public_key: 'key', user_data: '#cloud-config')
125
+ ud_item = result[:metadata][:items].find { |i| i[:key] == 'user-data' }
126
+ assert_equal '#cloud-config', ud_item[:value]
127
+ end
128
+
129
+ it 'omits user-data when blank' do
130
+ result = subject.for_new(username: 'user', public_key: 'key')
131
+ keys = result[:metadata][:items].map { |i| i[:key] }
132
+ assert_not_includes keys, 'user-data'
133
+ end
134
+ end
135
+
136
+ it 'passes through machine_type and image_id' do
137
+ result = subject.for_new(machine_type: 'e2-micro', image_id: '42')
138
+ assert_equal 'e2-micro', result[:machine_type]
139
+ assert_equal '42', result[:image_id]
140
+ end
141
+ end
142
+
143
+ describe '#for_create' do
144
+ let(:instance) do
145
+ vol1 = Google::Cloud::Compute::V1::AttachedDisk.new(device_name: 'vm-disk1')
146
+ vol2 = Google::Cloud::Compute::V1::AttachedDisk.new(device_name: 'vm-disk2')
147
+ OpenStruct.new(
148
+ name: 'test-vm',
149
+ zone: 'us-east1-b',
150
+ machine_type: 'e2-micro',
151
+ volumes: [vol1, vol2],
152
+ network_interfaces: [{ network: 'global/networks/default' }],
153
+ metadata: { items: [{ key: 'ssh-keys', value: 'user:key' }] }
154
+ )
155
+ end
156
+
157
+ it 'builds machine_type URL from zone' do
158
+ result = subject.for_create(instance)
159
+ assert_equal 'zones/us-east1-b/machineTypes/e2-micro', result[:machine_type]
160
+ end
161
+
162
+ it 'builds disk source paths' do
163
+ result = subject.for_create(instance)
164
+ assert_equal 'zones/us-east1-b/disks/vm-disk1', result[:disks][0][:source]
165
+ assert_equal 'zones/us-east1-b/disks/vm-disk2', result[:disks][1][:source]
166
+ end
167
+
168
+ it 'marks first disk as boot' do
169
+ result = subject.for_create(instance)
170
+ assert result[:disks][0][:boot]
171
+ assert_not result[:disks][1][:boot]
172
+ end
173
+
174
+ it 'includes network_interfaces and metadata' do
175
+ result = subject.for_create(instance)
176
+ assert_equal instance.network_interfaces, result[:network_interfaces]
177
+ assert_equal instance.metadata, result[:metadata]
178
+ end
179
+
180
+ it 'includes name' do
181
+ result = subject.for_create(instance)
182
+ assert_equal 'test-vm', result[:name]
183
+ end
184
+ end
185
+
186
+ describe '#for_instance' do
187
+ let(:nics) do
188
+ [OpenStruct.new(network: 'projects/my-project/global/networks/custom', network_i_p: '10.0.0.1')]
189
+ end
190
+ let(:instance) do
191
+ OpenStruct.new(
192
+ name: 'existing-vm',
193
+ creation_timestamp: Time.zone.parse('2024-01-15 10:00:00'),
194
+ zone: 'projects/my-project/zones/us-west1-a',
195
+ machine_type: 'zones/us-west1-a/machineTypes/n1-standard-1',
196
+ network_interfaces: nics,
197
+ disks: [OpenStruct.new(device_name: 'disk1')],
198
+ metadata: { items: [] }
199
+ )
200
+ end
201
+
202
+ it 'extracts zone_name from full zone URL' do
203
+ result = subject.for_instance(instance)
204
+ assert_equal 'us-west1-a', result[:zone_name]
205
+ end
206
+
207
+ it 'extracts network name from full URL' do
208
+ result = subject.for_instance(instance)
209
+ assert_equal 'custom', result[:network]
210
+ end
211
+
212
+ it 'converts creation_timestamp to DateTime' do
213
+ result = subject.for_instance(instance)
214
+ assert_kind_of DateTime, result[:creation_timestamp]
215
+ end
216
+
217
+ it 'passes through name and hostname' do
218
+ result = subject.for_instance(instance)
219
+ assert_equal 'existing-vm', result[:name]
220
+ assert_equal 'existing-vm', result[:hostname]
221
+ end
222
+
223
+ it 'passes through disks as volumes and metadata' do
224
+ result = subject.for_instance(instance)
225
+ assert_equal instance.disks, result[:volumes]
226
+ assert_equal instance.metadata, result[:metadata]
227
+ end
228
+
229
+ it 'passes through machine_type' do
230
+ result = subject.for_instance(instance)
231
+ assert_equal instance.machine_type, result[:machine_type]
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_google_helper'
2
+
3
+ module GoogleCloudCompute
4
+ class ComputeCollectionTest < GoogleTestCase
5
+ let(:client) { mock('GoogleAdapter') }
6
+ let(:zone) { 'us-east1-b' }
7
+
8
+ setup do
9
+ client.stubs(:project_id).returns('project_id')
10
+ end
11
+
12
+ describe 'with instances' do
13
+ let(:instances) do
14
+ nics = [OpenStruct.new(access_configs: [OpenStruct.new(nat_i_p: '1.2.3.4')],
15
+ network: 'projects/project_id/global/networks/default', network_i_p: '10.0.0.1')]
16
+ [
17
+ OpenStruct.new(id: 1, name: 'vm-1', network_interfaces: nics,
18
+ creation_timestamp: Time.zone.now, zone: zone, machine_type: 'machineTypes/e2-micro'),
19
+ OpenStruct.new(id: 2, name: 'vm-2', network_interfaces: nics,
20
+ creation_timestamp: Time.zone.now, zone: zone, machine_type: 'machineTypes/e2-small'),
21
+ ]
22
+ end
23
+
24
+ setup do
25
+ client.stubs(:instances).with(zone).returns(instances)
26
+ end
27
+
28
+ it 'wraps instances as GoogleCompute objects' do
29
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
30
+ collection.each do |vm|
31
+ assert_kind_of ForemanGoogle::GoogleCompute, vm
32
+ end
33
+ end
34
+
35
+ it 'iterates via each' do
36
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
37
+ names = collection.map(&:name)
38
+ assert_equal %w[vm-1 vm-2], names
39
+ end
40
+
41
+ it 'returns all VMs via all' do
42
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
43
+ assert_equal 2, collection.all.length
44
+ end
45
+
46
+ it 'is Enumerable' do
47
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
48
+ assert_kind_of Enumerable, collection
49
+ assert_equal 2, collection.count
50
+ end
51
+ end
52
+
53
+ describe 'with empty instance list' do
54
+ setup do
55
+ client.stubs(:instances).with(zone).returns([])
56
+ end
57
+
58
+ it 'returns empty collection' do
59
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
60
+ assert_empty collection.all
61
+ end
62
+
63
+ it 'iterates zero times' do
64
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
65
+ count = 0
66
+ collection.each { count += 1 }
67
+ assert_equal 0, count
68
+ end
69
+ end
70
+
71
+ describe 'with attrs' do
72
+ it 'passes attrs to client.instances' do
73
+ client.expects(:instances).with(zone, filter: 'name = "test"').returns([])
74
+ GoogleCloudCompute::ComputeCollection.new(client, zone, filter: 'name = "test"')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -12,6 +12,41 @@ module GoogleExtensions
12
12
  disk = Google::Cloud::Compute::V1::AttachedDisk.new
13
13
  assert_empty disk.insert_attrs[:source_image]
14
14
  end
15
+
16
+ it 'includes device_name as name' do
17
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new(device_name: 'boot-disk', disk_size_gb: 30)
18
+ attrs = disk.insert_attrs
19
+ assert_equal 'boot-disk', attrs[:name]
20
+ assert_equal 30, attrs[:size_gb]
21
+ end
22
+ end
23
+
24
+ describe '#size_gb' do
25
+ it 'returns disk_size_gb' do
26
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new(disk_size_gb: 50)
27
+ assert_equal 50, disk.size_gb
28
+ end
29
+ end
30
+
31
+ describe '#persisted?' do
32
+ it 'returns nil' do
33
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new
34
+ assert_nil disk.persisted?
35
+ end
36
+ end
37
+
38
+ describe '#id' do
39
+ it 'returns nil' do
40
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new
41
+ assert_nil disk.id
42
+ end
43
+ end
44
+
45
+ describe '#_delete' do
46
+ it 'returns nil' do
47
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new
48
+ assert_nil disk._delete
49
+ end
15
50
  end
16
51
  end
17
52
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_google
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.8
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Foreman Team
@@ -141,6 +141,7 @@ files:
141
141
  - locale/zh_TW/LC_MESSAGES/foreman_google.mo
142
142
  - locale/zh_TW/foreman_google.po
143
143
  - package.json
144
+ - test/controllers/foreman_google/api/v2/compute_resources_extensions_test.rb
144
145
  - test/factories/gce.rb
145
146
  - test/fixtures/disks_delete.json
146
147
  - test/fixtures/disks_get.json
@@ -160,10 +161,13 @@ files:
160
161
  - test/fixtures/operation_error.json
161
162
  - test/fixtures/operation_get.json
162
163
  - test/fixtures/zones.json
164
+ - test/models/concerns/foreman_google/host_managed_extensions_test.rb
163
165
  - test/models/foreman_google/gce_test.rb
164
166
  - test/models/foreman_google/google_compute_test.rb
165
167
  - test/test_google_helper.rb
166
168
  - test/unit/foreman_google/google_compute_adapter_test.rb
169
+ - test/unit/google_cloud_compute/compute_attributes_test.rb
170
+ - test/unit/google_cloud_compute/compute_collection_test.rb
167
171
  - test/unit/google_extensions/attached_disk_test.rb
168
172
  - webpack/global_index.js
169
173
  - webpack/global_test_setup.js
@@ -196,10 +200,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
200
  - !ruby/object:Gem::Version
197
201
  version: '0'
198
202
  requirements: []
199
- rubygems_version: 4.0.6
203
+ rubygems_version: 4.0.20
200
204
  specification_version: 4
201
205
  summary: Google Compute Engine plugin for the Foreman
202
206
  test_files:
207
+ - test/controllers/foreman_google/api/v2/compute_resources_extensions_test.rb
203
208
  - test/factories/gce.rb
204
209
  - test/fixtures/disks_delete.json
205
210
  - test/fixtures/disks_get.json
@@ -219,8 +224,11 @@ test_files:
219
224
  - test/fixtures/operation_error.json
220
225
  - test/fixtures/operation_get.json
221
226
  - test/fixtures/zones.json
227
+ - test/models/concerns/foreman_google/host_managed_extensions_test.rb
222
228
  - test/models/foreman_google/gce_test.rb
223
229
  - test/models/foreman_google/google_compute_test.rb
224
230
  - test/test_google_helper.rb
225
231
  - test/unit/foreman_google/google_compute_adapter_test.rb
232
+ - test/unit/google_cloud_compute/compute_attributes_test.rb
233
+ - test/unit/google_cloud_compute/compute_collection_test.rb
226
234
  - test/unit/google_extensions/attached_disk_test.rb