kube_cluster 0.3.7 → 0.3.8

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.
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ if __FILE__ == $0
4
+ require "bundler/setup"
5
+ require "kube/cluster"
6
+ end
7
+
3
8
  require "tempfile"
4
9
  require "yaml"
5
10
 
@@ -201,3 +206,408 @@ module Kube
201
206
  end
202
207
  end
203
208
  end
209
+
210
+ if __FILE__ == $0
211
+ require "minitest/autorun"
212
+
213
+ class ChartTest < Minitest::Test
214
+ # ── initialization ────────────────────────────────────────────────────
215
+
216
+ def test_initializes_with_data_hash
217
+ chart = Kube::Helm::Chart.new({ "name" => "my-app", "version" => "1.0.0", "appVersion" => "2.5.0" })
218
+ assert_equal "my-app", chart.name
219
+ assert_equal "1.0.0", chart.version
220
+ assert_equal "2.5.0", chart.app_version
221
+ end
222
+
223
+ def test_initializes_with_block
224
+ chart = Kube::Helm::Chart.new {
225
+ self.name = "my-app"
226
+ self.version = "1.0.0"
227
+ self.appVersion = "2.5.0"
228
+ self.description = "A test chart"
229
+ }
230
+
231
+ assert_equal "my-app", chart.name
232
+ assert_equal "1.0.0", chart.version
233
+ assert_equal "2.5.0", chart.app_version
234
+ assert_equal "A test chart", chart.description
235
+ end
236
+
237
+ def test_initializes_empty
238
+ chart = Kube::Helm::Chart.new
239
+ assert_nil chart.name
240
+ assert_nil chart.version
241
+ assert_nil chart.app_version
242
+ assert_nil chart.description
243
+ assert_nil chart.type
244
+ assert_equal [], chart.dependencies
245
+ end
246
+
247
+ def test_initializes_with_path
248
+ chart = Kube::Helm::Chart.new({ "name" => "x" }, path: "/tmp/charts/x")
249
+ assert_equal "/tmp/charts/x", chart.path
250
+ end
251
+
252
+ def test_initializes_with_cluster
253
+ cluster = Kube::Cluster.connect(kubeconfig: "/tmp/test-kubeconfig")
254
+ chart = Kube::Helm::Chart.new({ "name" => "x" }, cluster: cluster)
255
+ assert_equal cluster, chart.cluster
256
+ end
257
+
258
+ # ── Chart.open ───────────────────────────────────────────────────────
259
+
260
+ def test_open_reads_chart_yaml
261
+ Dir.mktmpdir do |dir|
262
+ File.write(File.join(dir, "Chart.yaml"), {
263
+ "name" => "test-chart",
264
+ "version" => "0.1.0",
265
+ "appVersion" => "1.0.0",
266
+ "description" => "A test chart",
267
+ "type" => "application",
268
+ }.to_yaml)
269
+
270
+ chart = Kube::Helm::Chart.open(dir)
271
+ assert_equal "test-chart", chart.name
272
+ assert_equal "0.1.0", chart.version
273
+ assert_equal "1.0.0", chart.app_version
274
+ assert_equal "A test chart", chart.description
275
+ assert_equal "application", chart.type
276
+ assert_equal dir, chart.path
277
+ end
278
+ end
279
+
280
+ def test_open_raises_without_chart_yaml
281
+ Dir.mktmpdir do |dir|
282
+ assert_raises(Kube::Error) { Kube::Helm::Chart.open(dir) }
283
+ end
284
+ end
285
+
286
+ def test_open_with_cluster
287
+ Dir.mktmpdir do |dir|
288
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "x", "version" => "1.0.0" }.to_yaml)
289
+ cluster = Kube::Cluster.connect(kubeconfig: "/tmp/test-kubeconfig")
290
+
291
+ chart = Kube::Helm::Chart.open(dir, cluster: cluster)
292
+ assert_equal cluster, chart.cluster
293
+ end
294
+ end
295
+
296
+ # ── to_s ──────────────────────────────────────────────────────────────
297
+
298
+ def test_to_s_with_version
299
+ chart = Kube::Helm::Chart.new({ "name" => "nginx", "version" => "18.1.0" })
300
+ assert_equal "nginx:18.1.0", chart.to_s
301
+ end
302
+
303
+ def test_to_s_without_version
304
+ chart = Kube::Helm::Chart.new({ "name" => "nginx" })
305
+ assert_equal "nginx", chart.to_s
306
+ end
307
+
308
+ # ── apply_values ─────────────────────────────────────────────────────
309
+
310
+ def test_apply_values_raises_without_source
311
+ chart = Kube::Helm::Chart.new({ "name" => "my-app" })
312
+ assert_raises(Kube::Error) { chart.apply_values({ "replicaCount" => 3 }) }
313
+ end
314
+
315
+ def test_apply_values_builds_correct_command
316
+ Dir.mktmpdir do |dir|
317
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
318
+ chart = Kube::Helm::Chart.open(dir)
319
+
320
+ captured_cmd = nil
321
+ stub_yaml = { "kind" => "Deployment", "apiVersion" => "apps/v1", "metadata" => { "name" => "web" } }.to_yaml
322
+
323
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
324
+ chart.apply_values({ "replicaCount" => 3 })
325
+ end
326
+
327
+ assert_includes captured_cmd, "template"
328
+ assert_includes captured_cmd, "my-app"
329
+ assert_includes captured_cmd, dir
330
+ assert_match(/-f .*helm-values.*\.yaml/, captured_cmd)
331
+ end
332
+ end
333
+
334
+ def test_apply_values_with_custom_release
335
+ Dir.mktmpdir do |dir|
336
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
337
+ chart = Kube::Helm::Chart.open(dir)
338
+
339
+ captured_cmd = nil
340
+ stub_yaml = { "kind" => "Pod", "apiVersion" => "v1" }.to_yaml
341
+
342
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
343
+ chart.apply_values({}, release: "custom-release")
344
+ end
345
+
346
+ assert_includes captured_cmd, "custom-release"
347
+ end
348
+ end
349
+
350
+ def test_apply_values_with_namespace
351
+ Dir.mktmpdir do |dir|
352
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
353
+ chart = Kube::Helm::Chart.open(dir)
354
+
355
+ captured_cmd = nil
356
+ stub_yaml = { "kind" => "Pod", "apiVersion" => "v1" }.to_yaml
357
+
358
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
359
+ chart.apply_values({}, namespace: "production")
360
+ end
361
+
362
+ assert_includes captured_cmd, "--namespace=production"
363
+ end
364
+ end
365
+
366
+ def test_apply_values_returns_manifest
367
+ Dir.mktmpdir do |dir|
368
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
369
+ chart = Kube::Helm::Chart.open(dir)
370
+
371
+ stub_yaml = [
372
+ { "kind" => "Deployment", "apiVersion" => "apps/v1", "metadata" => { "name" => "web" } },
373
+ { "kind" => "Service", "apiVersion" => "v1", "metadata" => { "name" => "web" } },
374
+ ].map(&:to_yaml).join("")
375
+
376
+ result = nil
377
+ Kube::Helm.stub(:run, ->(_cmd) { stub_yaml }) do
378
+ result = chart.apply_values({ "replicaCount" => 3 })
379
+ end
380
+
381
+ assert_instance_of Kube::Schema::Manifest, result
382
+ assert_equal 2, result.count
383
+
384
+ kinds = result.map(&:kind)
385
+ assert_includes kinds, "Deployment"
386
+ assert_includes kinds, "Service"
387
+ end
388
+ end
389
+
390
+ def test_apply_values_defaults_release_to_chart_name
391
+ Dir.mktmpdir do |dir|
392
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "nginx", "version" => "1.0.0" }.to_yaml)
393
+ chart = Kube::Helm::Chart.open(dir)
394
+
395
+ captured_cmd = nil
396
+ stub_yaml = { "kind" => "Pod", "apiVersion" => "v1" }.to_yaml
397
+
398
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
399
+ chart.apply_values({})
400
+ end
401
+
402
+ assert_includes captured_cmd, "nginx"
403
+ end
404
+ end
405
+
406
+ # ── show_values ──────────────────────────────────────────────────────
407
+
408
+ def test_show_values
409
+ Dir.mktmpdir do |dir|
410
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
411
+ chart = Kube::Helm::Chart.open(dir)
412
+
413
+ captured_cmd = nil
414
+ stub_yaml = { "replicaCount" => 1, "service" => { "type" => "ClusterIP" } }.to_yaml
415
+
416
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
417
+ result = chart.show_values
418
+ assert_equal 1, result["replicaCount"]
419
+ assert_equal "ClusterIP", result.dig("service", "type")
420
+ end
421
+
422
+ assert_includes captured_cmd, "show"
423
+ assert_includes captured_cmd, "values"
424
+ assert_includes captured_cmd, dir
425
+ end
426
+ end
427
+
428
+ def test_show_values_raises_without_source
429
+ chart = Kube::Helm::Chart.new({ "name" => "my-app" })
430
+ assert_raises(Kube::Error) { chart.show_values }
431
+ end
432
+
433
+ # ── crds ─────────────────────────────────────────────────────────────
434
+
435
+ def test_crds_returns_custom_resource_definition_objects
436
+ Dir.mktmpdir do |dir|
437
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "cert-manager", "version" => "1.0.0" }.to_yaml)
438
+ chart = Kube::Helm::Chart.open(dir)
439
+
440
+ stub_yaml = [
441
+ { "kind" => "Deployment", "apiVersion" => "apps/v1", "metadata" => { "name" => "cm" } },
442
+ {
443
+ "kind" => "CustomResourceDefinition",
444
+ "apiVersion" => "apiextensions.k8s.io/v1",
445
+ "metadata" => { "name" => "clusterissuers.cert-manager.io" },
446
+ "spec" => {
447
+ "group" => "cert-manager.io",
448
+ "names" => { "kind" => "ClusterIssuer" },
449
+ "versions" => [
450
+ {
451
+ "name" => "v1",
452
+ "schema" => {
453
+ "openAPIV3Schema" => {
454
+ "type" => "object",
455
+ "properties" => { "spec" => { "type" => "object" } },
456
+ },
457
+ },
458
+ },
459
+ ],
460
+ },
461
+ },
462
+ ].map(&:to_yaml).join("")
463
+
464
+ result = nil
465
+ Kube::Helm.stub(:run, ->(_cmd) { stub_yaml }) do
466
+ result = chart.crds
467
+ end
468
+
469
+ assert_equal 1, result.length
470
+ assert_equal "CustomResourceDefinition", result.first.kind
471
+ assert result.first.respond_to?(:to_json_schema)
472
+ end
473
+ end
474
+
475
+ def test_crds_raises_without_source
476
+ chart = Kube::Helm::Chart.new({ "name" => "my-app" })
477
+ assert_raises(Kube::Error) { chart.crds }
478
+ end
479
+
480
+ # ── cluster scoping ──────────────────────────────────────────────────
481
+
482
+ def test_apply_values_uses_cluster_helm_instance
483
+ Dir.mktmpdir do |dir|
484
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
485
+ cluster = Kube::Cluster.connect(kubeconfig: "/tmp/test-kubeconfig")
486
+ chart = Kube::Helm::Chart.open(dir, cluster: cluster)
487
+
488
+ captured_cmd = nil
489
+ stub_yaml = { "kind" => "Pod", "apiVersion" => "v1" }.to_yaml
490
+
491
+ cluster.connection.helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
492
+ chart.apply_values({ "foo" => "bar" })
493
+ end
494
+
495
+ assert_includes captured_cmd, "template"
496
+ assert_includes captured_cmd, "my-app"
497
+ end
498
+ end
499
+
500
+ def test_show_values_uses_cluster_helm_instance
501
+ Dir.mktmpdir do |dir|
502
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
503
+ cluster = Kube::Cluster.connect(kubeconfig: "/tmp/test-kubeconfig")
504
+ chart = Kube::Helm::Chart.open(dir, cluster: cluster)
505
+
506
+ captured_cmd = nil
507
+ stub_yaml = { "replicaCount" => 1 }.to_yaml
508
+
509
+ cluster.connection.helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
510
+ chart.show_values
511
+ end
512
+
513
+ assert_includes captured_cmd, "show"
514
+ assert_includes captured_cmd, "values"
515
+ end
516
+ end
517
+
518
+ # ── remote chart (ref-based) ─────────────────────────────────────────
519
+
520
+ def test_initializes_with_ref
521
+ chart = Kube::Helm::Chart.new({ "name" => "nginx", "version" => "18.1.0" }, ref: "bitnami/nginx")
522
+ assert_equal "bitnami/nginx", chart.ref
523
+ assert_nil chart.path
524
+ end
525
+
526
+ def test_apply_values_with_ref_uses_ref_and_version
527
+ chart = Kube::Helm::Chart.new(
528
+ { "name" => "nginx", "version" => "18.1.0" },
529
+ ref: "bitnami/nginx"
530
+ )
531
+
532
+ captured_cmd = nil
533
+ stub_yaml = { "kind" => "Deployment", "apiVersion" => "apps/v1", "metadata" => { "name" => "web" } }.to_yaml
534
+
535
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
536
+ chart.apply_values({ "replicaCount" => 3 })
537
+ end
538
+
539
+ assert_includes captured_cmd, "template"
540
+ assert_includes captured_cmd, "nginx"
541
+ assert_includes captured_cmd, "bitnami/nginx"
542
+ assert_includes captured_cmd, "--version=18.1.0"
543
+ end
544
+
545
+ def test_apply_values_with_path_does_not_add_version_flag
546
+ Dir.mktmpdir do |dir|
547
+ File.write(File.join(dir, "Chart.yaml"), { "name" => "my-app", "version" => "1.0.0" }.to_yaml)
548
+ chart = Kube::Helm::Chart.open(dir)
549
+
550
+ captured_cmd = nil
551
+ stub_yaml = { "kind" => "Pod", "apiVersion" => "v1" }.to_yaml
552
+
553
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
554
+ chart.apply_values({})
555
+ end
556
+
557
+ refute_includes captured_cmd, "--version"
558
+ end
559
+ end
560
+
561
+ def test_show_values_with_ref
562
+ chart = Kube::Helm::Chart.new(
563
+ { "name" => "nginx", "version" => "18.1.0" },
564
+ ref: "bitnami/nginx"
565
+ )
566
+
567
+ captured_cmd = nil
568
+ stub_yaml = { "replicaCount" => 1 }.to_yaml
569
+
570
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
571
+ chart.show_values
572
+ end
573
+
574
+ assert_includes captured_cmd, "show"
575
+ assert_includes captured_cmd, "values"
576
+ assert_includes captured_cmd, "bitnami/nginx"
577
+ assert_includes captured_cmd, "--version=18.1.0"
578
+ end
579
+
580
+ def test_crds_with_ref
581
+ chart = Kube::Helm::Chart.new(
582
+ { "name" => "cert-manager", "version" => "1.17.2" },
583
+ ref: "jetstack/cert-manager"
584
+ )
585
+
586
+ stub_yaml = [
587
+ {
588
+ "kind" => "CustomResourceDefinition",
589
+ "apiVersion" => "apiextensions.k8s.io/v1",
590
+ "metadata" => { "name" => "issuers.cert-manager.io" },
591
+ "spec" => {
592
+ "group" => "cert-manager.io",
593
+ "names" => { "kind" => "Issuer" },
594
+ "versions" => [
595
+ { "name" => "v1", "schema" => { "openAPIV3Schema" => { "type" => "object" } } },
596
+ ],
597
+ },
598
+ },
599
+ ].map(&:to_yaml).join("")
600
+
601
+ captured_cmd = nil
602
+ Kube::Helm.stub(:run, ->(cmd) { captured_cmd = cmd; stub_yaml }) do
603
+ result = chart.crds
604
+ assert_equal 1, result.length
605
+ end
606
+
607
+ assert_includes captured_cmd, "show"
608
+ assert_includes captured_cmd, "crds"
609
+ assert_includes captured_cmd, "jetstack/cert-manager"
610
+ assert_includes captured_cmd, "--version=1.17.2"
611
+ end
612
+ end
613
+ end
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ if __FILE__ == $0
4
+ require "bundler/setup"
5
+ require "kube/cluster"
6
+ end
7
+
3
8
  module Kube
4
9
  module Helm
5
10
  # Abstracts the differences between Helm chart sources.
@@ -73,3 +78,84 @@ module Kube
73
78
  end
74
79
  end
75
80
  end
81
+
82
+ if __FILE__ == $0
83
+ require "minitest/autorun"
84
+
85
+ class EndpointTest < Minitest::Test
86
+ # ── OCI detection ──────────────────────────────────────────────────────
87
+
88
+ def test_oci_endpoint_detected
89
+ endpoint = Kube::Helm::Endpoint.new("oci://ghcr.io/my-org/charts")
90
+ assert endpoint.oci?
91
+ end
92
+
93
+ def test_http_endpoint_not_oci
94
+ endpoint = Kube::Helm::Endpoint.new("https://charts.bitnami.com/bitnami")
95
+ refute endpoint.oci?
96
+ end
97
+
98
+ # ── requires_add? ─────────────────────────────────────────────────────
99
+
100
+ def test_oci_does_not_require_add
101
+ endpoint = Kube::Helm::Endpoint.new("oci://ghcr.io/my-org/charts")
102
+ refute endpoint.requires_add?
103
+ end
104
+
105
+ def test_http_requires_add
106
+ endpoint = Kube::Helm::Endpoint.new("https://charts.bitnami.com/bitnami")
107
+ assert endpoint.requires_add?
108
+ end
109
+
110
+ # ── chart_ref ──────────────────────────────────────────────────────────
111
+
112
+ def test_oci_chart_ref
113
+ endpoint = Kube::Helm::Endpoint.new("oci://ghcr.io/my-org/charts")
114
+ assert_equal "oci://ghcr.io/my-org/charts/nginx", endpoint.chart_ref("nginx")
115
+ end
116
+
117
+ def test_oci_chart_ref_strips_trailing_slash
118
+ endpoint = Kube::Helm::Endpoint.new("oci://ghcr.io/my-org/charts/")
119
+ assert_equal "oci://ghcr.io/my-org/charts/nginx", endpoint.chart_ref("nginx")
120
+ end
121
+
122
+ def test_http_chart_ref_with_repo_name
123
+ endpoint = Kube::Helm::Endpoint.new("https://charts.bitnami.com/bitnami")
124
+ assert_equal "bitnami/nginx", endpoint.chart_ref("nginx", repo_name: "bitnami")
125
+ end
126
+
127
+ def test_http_chart_ref_raises_without_repo_name
128
+ endpoint = Kube::Helm::Endpoint.new("https://charts.bitnami.com/bitnami")
129
+ assert_raises(ArgumentError) { endpoint.chart_ref("nginx") }
130
+ end
131
+
132
+ # ── validation ─────────────────────────────────────────────────────────
133
+
134
+ def test_raises_on_empty_url
135
+ assert_raises(ArgumentError) { Kube::Helm::Endpoint.new("") }
136
+ end
137
+
138
+ def test_raises_on_non_string_url
139
+ assert_raises(ArgumentError) { Kube::Helm::Endpoint.new(nil) }
140
+ end
141
+
142
+ # ── to_s / equality ───────────────────────────────────────────────────
143
+
144
+ def test_to_s_returns_url
145
+ endpoint = Kube::Helm::Endpoint.new("https://charts.example.com")
146
+ assert_equal "https://charts.example.com", endpoint.to_s
147
+ end
148
+
149
+ def test_equality
150
+ a = Kube::Helm::Endpoint.new("https://charts.example.com")
151
+ b = Kube::Helm::Endpoint.new("https://charts.example.com")
152
+ assert_equal a, b
153
+ end
154
+
155
+ def test_inequality
156
+ a = Kube::Helm::Endpoint.new("https://charts.example.com")
157
+ b = Kube::Helm::Endpoint.new("oci://ghcr.io/my-org/charts")
158
+ refute_equal a, b
159
+ end
160
+ end
161
+ end