foreman_nutanix 0.1.4 → 0.1.6

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,257 @@
1
+ require 'test_helper'
2
+
3
+ class ShimClientTest < Minitest::Test
4
+ # --- Fakes injected through the http: keyword -----------------------------
5
+
6
+ # Stands in for a Net::HTTP connection object.
7
+ class FakeConnection
8
+ attr_reader :host, :port, :requests
9
+ attr_accessor :use_ssl
10
+
11
+ def initialize(host, port, response)
12
+ @host = host
13
+ @port = port
14
+ @response = response
15
+ @requests = []
16
+ @use_ssl = nil
17
+ end
18
+
19
+ def request(req)
20
+ @requests << req
21
+ @response
22
+ end
23
+ end
24
+
25
+ # Stands in for the Net::HTTP class itself.
26
+ class FakeHttp
27
+ attr_reader :connections
28
+
29
+ def initialize(response)
30
+ @response = response
31
+ @connections = []
32
+ end
33
+
34
+ def new(host, port)
35
+ conn = FakeConnection.new(host, port, @response)
36
+ @connections << conn
37
+ conn
38
+ end
39
+
40
+ def last_connection
41
+ @connections.last
42
+ end
43
+
44
+ def last_request
45
+ last_connection.requests.last
46
+ end
47
+ end
48
+
49
+ def stub_response(klass = Net::HTTPOK, code: '200', body: '{}')
50
+ response = klass.new('1.1', code, 'Stub')
51
+ response.instance_variable_set(:@body, body)
52
+ response.instance_variable_set(:@read, true)
53
+ response
54
+ end
55
+
56
+ def client(base_url = 'http://shim.example:8000', response: stub_response)
57
+ http = FakeHttp.new(response)
58
+ [ForemanNutanix::ShimClient.new(base_url, http: http), http]
59
+ end
60
+
61
+ def with_env(value)
62
+ previous = ENV['NUTANIX_SHIM_SERVER_ADDR']
63
+ had_key = ENV.key?('NUTANIX_SHIM_SERVER_ADDR')
64
+ if value.nil?
65
+ ENV.delete('NUTANIX_SHIM_SERVER_ADDR')
66
+ else
67
+ ENV['NUTANIX_SHIM_SERVER_ADDR'] = value
68
+ end
69
+ yield
70
+ ensure
71
+ if had_key
72
+ ENV['NUTANIX_SHIM_SERVER_ADDR'] = previous
73
+ else
74
+ ENV.delete('NUTANIX_SHIM_SERVER_ADDR')
75
+ end
76
+ end
77
+
78
+ # --- Base URL -------------------------------------------------------------
79
+
80
+ def test_base_url_defaults_to_localhost_when_env_is_unset
81
+ with_env(nil) do
82
+ assert_equal 'http://localhost:8000', ForemanNutanix::ShimClient.new.base_url
83
+ assert_equal 'http://localhost:8000', ForemanNutanix::ShimClient.default_base_url
84
+ end
85
+ end
86
+
87
+ def test_base_url_comes_from_env_when_set
88
+ with_env('http://shim.internal:9000') do
89
+ assert_equal 'http://shim.internal:9000', ForemanNutanix::ShimClient.new.base_url
90
+ assert_equal 'http://shim.internal:9000', ForemanNutanix::ShimClient.default_base_url
91
+ end
92
+ end
93
+
94
+ def test_explicit_base_url_wins_over_env
95
+ with_env('http://shim.internal:9000') do
96
+ assert_equal 'http://explicit:1234', ForemanNutanix::ShimClient.new('http://explicit:1234').base_url
97
+ end
98
+ end
99
+
100
+ def test_trailing_slash_is_chomped
101
+ shim = ForemanNutanix::ShimClient.new('http://shim.example:8000/')
102
+ assert_equal 'http://shim.example:8000', shim.base_url
103
+ end
104
+
105
+ def test_trailing_slash_from_env_is_chomped
106
+ with_env('http://shim.internal:9000/') do
107
+ assert_equal 'http://shim.internal:9000', ForemanNutanix::ShimClient.new.base_url
108
+ end
109
+ end
110
+
111
+ # --- Verbs and path construction -----------------------------------------
112
+
113
+ def test_get_builds_a_get_request_at_the_joined_path
114
+ shim, http = client
115
+ shim.get('/api/v1/vmm/list-images')
116
+
117
+ request = http.last_request
118
+ assert_instance_of Net::HTTP::Get, request
119
+ assert_equal '/api/v1/vmm/list-images', request.path
120
+ assert_equal 'shim.example', http.last_connection.host
121
+ assert_equal 8000, http.last_connection.port
122
+ end
123
+
124
+ def test_post_builds_a_post_request_at_the_joined_path
125
+ shim, http = client
126
+ shim.post('/api/v1/vmm/vms/abc/power-state', { action: 'POWER_ON' })
127
+
128
+ assert_instance_of Net::HTTP::Post, http.last_request
129
+ assert_equal '/api/v1/vmm/vms/abc/power-state', http.last_request.path
130
+ end
131
+
132
+ def test_delete_builds_a_delete_request_at_the_joined_path
133
+ shim, http = client
134
+ shim.delete('/api/v1/vmm/vms/abc')
135
+
136
+ assert_instance_of Net::HTTP::Delete, http.last_request
137
+ assert_equal '/api/v1/vmm/vms/abc', http.last_request.path
138
+ end
139
+
140
+ def test_path_is_joined_to_a_base_url_that_had_a_trailing_slash
141
+ http = FakeHttp.new(stub_response)
142
+ ForemanNutanix::ShimClient.new('http://shim.example:8000/', http: http).get('/api/v1/vmm/list-vms')
143
+
144
+ assert_equal '/api/v1/vmm/list-vms', http.last_request.path
145
+ end
146
+
147
+ # --- Body encoding --------------------------------------------------------
148
+
149
+ def test_post_json_encodes_the_body_and_sets_content_type
150
+ shim, http = client
151
+ shim.post('/api/v1/vmm/provision-vm', { name: 'vm-1', num_sockets: 2 })
152
+
153
+ assert_equal 'application/json', http.last_request['Content-Type']
154
+ assert_equal({ 'name' => 'vm-1', 'num_sockets' => 2 }, JSON.parse(http.last_request.body))
155
+ end
156
+
157
+ def test_post_without_a_body_sends_no_body_and_no_content_type
158
+ shim, http = client
159
+ shim.post('/api/v1/vmm/noop')
160
+
161
+ assert_nil http.last_request.body
162
+ assert_nil http.last_request['Content-Type']
163
+ end
164
+
165
+ def test_get_sends_no_body_and_no_content_type
166
+ shim, http = client
167
+ shim.get('/api/v1/vmm/list-vms')
168
+
169
+ assert_nil http.last_request.body
170
+ assert_nil http.last_request['Content-Type']
171
+ end
172
+
173
+ # --- Scheme ---------------------------------------------------------------
174
+
175
+ def test_https_is_inferred_from_the_scheme
176
+ http = FakeHttp.new(stub_response)
177
+ ForemanNutanix::ShimClient.new('https://shim.example', http: http).get('/api/v1/vmm/list-vms')
178
+
179
+ assert_equal true, http.last_connection.use_ssl
180
+ assert_equal 443, http.last_connection.port
181
+ end
182
+
183
+ def test_http_scheme_does_not_enable_ssl
184
+ shim, http = client
185
+ shim.get('/api/v1/vmm/list-vms')
186
+
187
+ assert_equal false, http.last_connection.use_ssl
188
+ end
189
+
190
+ # --- Response -------------------------------------------------------------
191
+
192
+ def test_success_is_true_for_200
193
+ shim, = client(response: stub_response(Net::HTTPOK, code: '200'))
194
+ response = shim.get('/whatever')
195
+
196
+ assert_equal true, response.success?
197
+ assert_equal '200', response.code
198
+ end
199
+
200
+ def test_success_is_false_for_404
201
+ shim, = client(response: stub_response(Net::HTTPNotFound, code: '404', body: 'not found'))
202
+ response = shim.get('/whatever')
203
+
204
+ assert_equal false, response.success?
205
+ assert_equal '404', response.code
206
+ assert_equal 'not found', response.body
207
+ end
208
+
209
+ def test_success_is_false_for_500
210
+ error = stub_response(Net::HTTPInternalServerError, code: '500', body: '<html>boom</html>')
211
+ shim, = client(response: error)
212
+ response = shim.get('/whatever')
213
+
214
+ assert_equal false, response.success?
215
+ assert_equal '500', response.code
216
+ end
217
+
218
+ def test_no_content_is_true_only_for_204
219
+ shim, = client(response: stub_response(Net::HTTPNoContent, code: '204', body: nil))
220
+ assert_equal true, shim.get('/whatever').no_content?
221
+
222
+ shim_ok, = client(response: stub_response(Net::HTTPOK, code: '200'))
223
+ assert_equal false, shim_ok.get('/whatever').no_content?
224
+ end
225
+
226
+ def test_json_parses_the_body
227
+ shim, = client(response: stub_response(Net::HTTPOK, body: '[{"ext_id":"abc"}]'))
228
+
229
+ assert_equal [{ 'ext_id' => 'abc' }], shim.get('/whatever').json
230
+ end
231
+
232
+ def test_json_propagates_parser_error_on_non_json_bodies
233
+ error = stub_response(Net::HTTPInternalServerError, code: '500', body: '<html>boom</html>')
234
+ shim, = client(response: error)
235
+
236
+ assert_raises(JSON::ParserError) { shim.get('/whatever').json }
237
+ end
238
+
239
+ # --- normalize_uuid -------------------------------------------------------
240
+
241
+ def test_normalize_uuid_strips_a_prefix
242
+ assert_equal 'the-uuid', ForemanNutanix::ShimClient.normalize_uuid('ZXJnb24=:the-uuid')
243
+ end
244
+
245
+ def test_normalize_uuid_leaves_a_bare_uuid_alone
246
+ assert_equal 'the-uuid', ForemanNutanix::ShimClient.normalize_uuid('the-uuid')
247
+ end
248
+
249
+ def test_normalize_uuid_coerces_non_strings
250
+ assert_equal '', ForemanNutanix::ShimClient.normalize_uuid(nil)
251
+ assert_equal '42', ForemanNutanix::ShimClient.normalize_uuid(42)
252
+ end
253
+
254
+ def test_normalize_uuid_keeps_only_the_last_segment
255
+ assert_equal 'c', ForemanNutanix::ShimClient.normalize_uuid('a:b:c')
256
+ end
257
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+
3
+ # Standalone: no Rails, no Foreman, no database. See test/README.md for what
4
+ # that rules out.
5
+ require 'foreman_nutanix/shim_client'
6
+
7
+ # NutanixCompute is a plain object, but it logs in nearly every method. This is
8
+ # the whole of the Rails surface the suite needs; it lives here rather than in
9
+ # one test file so a second file defining it cannot redefine the first's.
10
+ require 'logger'
11
+ module Rails
12
+ def self.logger
13
+ @logger ||= Logger.new(IO::NULL)
14
+ end
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_nutanix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Granger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-14 00:00:00.000000000 Z
11
+ date: 2026-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -54,10 +54,18 @@ files:
54
54
  - config/routes.rb
55
55
  - lib/foreman_nutanix.rb
56
56
  - lib/foreman_nutanix/engine.rb
57
+ - lib/foreman_nutanix/gpu_profile.rb
58
+ - lib/foreman_nutanix/shim_client.rb
57
59
  - lib/foreman_nutanix/version.rb
58
60
  - lib/tasks/foreman_nutanix_tasks.rake
59
61
  - locale/foreman_nutanix.pot
60
62
  - package.json
63
+ - test/README.md
64
+ - test/gpu_profile_test.rb
65
+ - test/nutanix_compute_gpu_test.rb
66
+ - test/nutanix_compute_test.rb
67
+ - test/shim_client_test.rb
68
+ - test/test_helper.rb
61
69
  - webpack/global_index.js
62
70
  - webpack/global_test_setup.js
63
71
  - webpack/index.js
@@ -94,4 +102,10 @@ rubygems_version: 3.4.19
94
102
  signing_key:
95
103
  specification_version: 4
96
104
  summary: Nutanix plugin for Foreman
97
- test_files: []
105
+ test_files:
106
+ - test/README.md
107
+ - test/gpu_profile_test.rb
108
+ - test/nutanix_compute_gpu_test.rb
109
+ - test/nutanix_compute_test.rb
110
+ - test/shim_client_test.rb
111
+ - test/test_helper.rb