kube_schema 1.12.0 → 2.0.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.
@@ -2,28 +2,19 @@
2
2
 
3
3
  module Kube
4
4
  module Schema
5
- # A lightweight, schema-validated wrapper for non-resource Kubernetes
6
- # definitions — things like Container, ContainerPort, Volume, Probe,
7
- # etc. that live inside resource specs but have no apiVersion/kind.
8
- #
9
- # SubSpec validates against the OpenAPI JSON Schema definition and
10
- # produces a plain Hash via #to_h, suitable for embedding directly
11
- # inside Resource specs.
5
+ # A schema-validated wrapper for non-resource Kubernetes definitions.
12
6
  #
7
+ # @example
13
8
  # container = Kube::Schema::SubSpec["Container"].new {
14
9
  # name = "app"
15
10
  # image = "nginx:1.27"
16
11
  # ports = [{ containerPort: 80 }]
17
12
  # }
18
- #
19
13
  # container.valid? # => true
20
14
  # container.to_h # => { name: "app", image: "nginx:1.27", ... }
21
15
  #
22
- # SubSpec instances auto-coerce when placed inside a Resource —
23
- # no explicit .to_h is needed:
24
- #
16
+ # @example Auto-coerces inside a Resource, no #to_h needed
25
17
  # spec.template.spec.containers = [container]
26
- #
27
18
  class SubSpec
28
19
 
29
20
  def initialize(hash = {}, &block)
@@ -42,7 +33,8 @@ module Kube
42
33
  end
43
34
  end
44
35
 
45
- # Gets overridden by the factory in Kube::Schema::Instance
36
+ # Overridden by the factory in Kube::Schema::Instance.
37
+ # @returns [JSONSchemer::Schema, nil] the schema, once overridden.
46
38
  def self.schema
47
39
  raise "Kube::Schema::SubSpec should NOT be instantiated directly"
48
40
  end
@@ -63,7 +55,9 @@ module Kube
63
55
  end
64
56
  end
65
57
 
66
- # Like #valid? but raises Kube::ValidationError with details on failure.
58
+ # Like #valid? but raises on failure.
59
+ # @returns [Boolean] true if the sub-spec is valid.
60
+ # @raises [Kube::ValidationError] with details on failure.
67
61
  def valid!
68
62
  if self.class.schema.nil?
69
63
  true
@@ -72,9 +66,10 @@ module Kube
72
66
  errors = self.class.schema.validate(data).to_a
73
67
 
74
68
  unless errors.empty?
75
- raise Kube::ValidationError.new(errors,
76
- kind: self.class.definition_name,
77
- manifest: data
69
+ raise Kube::ValidationError.new(
70
+ errors,
71
+ kind: self.class.definition_name,
72
+ manifest: data,
78
73
  )
79
74
  end
80
75
 
@@ -83,6 +78,7 @@ module Kube
83
78
  end
84
79
 
85
80
  # Returns the sub-spec data as a plain Hash.
81
+ # @returns [Hash] the sub-spec data, symbol-keyed.
86
82
  def to_h
87
83
  data = deep_compact(@data)
88
84
  data.reject { |_, v| v.is_a?(Hash) && v.empty? }
@@ -94,10 +90,10 @@ module Kube
94
90
 
95
91
  # Look up a sub-spec definition by short name.
96
92
  #
93
+ # @example
97
94
  # Kube::Schema::SubSpec["Container"]
98
95
  # Kube::Schema::SubSpec["ContainerPort"]
99
96
  # Kube::Schema::SubSpec["Volume"]
100
- #
101
97
  class << self
102
98
  def [](name)
103
99
  version = Schema.schema_version || Schema::DEFAULT_VERSION
@@ -113,7 +109,9 @@ module Kube
113
109
  when Hash
114
110
  obj.each_with_object({}) do |(k, v), result|
115
111
  compacted = deep_compact(v)
116
- result[k] = compacted unless compacted.nil?
112
+ unless compacted.nil?
113
+ result[k] = compacted
114
+ end
117
115
  end
118
116
  when Array
119
117
  obj.map { |v| deep_compact(v) }
@@ -151,335 +149,305 @@ module Kube
151
149
  end
152
150
  end
153
151
 
154
- if __FILE__ == $0
155
- require "bundler/setup"
156
- require "rspec/autorun"
157
- require "kube/schema"
158
-
159
- RSpec.describe Kube::Schema::SubSpec do
160
- describe ".[]" do
161
- it "returns a Class that subclasses SubSpec" do
162
- klass = described_class["Container"]
163
- expect(klass).to be_a(Class)
164
- expect(klass).to be < described_class
165
- end
166
152
 
167
- it "caches sub-spec classes by name" do
168
- a = described_class["Container"]
169
- b = described_class["Container"]
170
- expect(a).to be(b)
171
- end
172
-
173
- it "resolves ContainerPort" do
174
- klass = described_class["ContainerPort"]
175
- expect(klass).to be < described_class
176
- end
177
-
178
- it "resolves Probe" do
179
- klass = described_class["Probe"]
180
- expect(klass).to be < described_class
181
- end
153
+ __END__
182
154
 
183
- it "resolves Volume" do
184
- klass = described_class["Volume"]
185
- expect(klass).to be < described_class
186
- end
155
+ require "kube/schema"
187
156
 
188
- it "resolves EnvVar" do
189
- klass = described_class["EnvVar"]
190
- expect(klass).to be < described_class
191
- end
157
+ sub_spec = Kube::Schema::SubSpec
158
+ container = lambda { sub_spec["Container"] }
192
159
 
193
- it "resolves ResourceRequirements" do
194
- klass = described_class["ResourceRequirements"]
195
- expect(klass).to be < described_class
196
- end
160
+ describe "Kube::Schema::SubSpec" do
161
+ describe ".[]" do
162
+ it "returns a Class that subclasses SubSpec" do
163
+ klass = sub_spec["Container"]
164
+ klass.should.be.kind_of Class
165
+ klass.should.be < sub_spec
166
+ end
197
167
 
198
- it "resolves a full definition key" do
199
- klass = described_class["io.k8s.api.core.v1.Container"]
200
- expect(klass).to be < described_class
201
- end
168
+ it "caches sub-spec classes by name" do
169
+ sub_spec["Container"].should.be.identical_to sub_spec["Container"]
170
+ end
202
171
 
203
- it "raises for an unknown definition" do
204
- expect { described_class["ThisDoesNotExist999"] }.to raise_error(RuntimeError, /No definition found/)
205
- end
172
+ it "resolves ContainerPort" do
173
+ sub_spec["ContainerPort"].should.be < sub_spec
206
174
  end
207
175
 
208
- describe ".definition_name" do
209
- it "returns the short name used to look up the sub-spec" do
210
- klass = described_class["Container"]
211
- expect(klass.definition_name).to eq("Container")
212
- end
176
+ it "resolves Probe" do
177
+ sub_spec["Probe"].should.be < sub_spec
213
178
  end
214
179
 
215
- describe ".schema" do
216
- it "has a schema attached" do
217
- klass = described_class["Container"]
218
- expect(klass.schema).not_to be_nil
219
- end
180
+ it "resolves Volume" do
181
+ sub_spec["Volume"].should.be < sub_spec
220
182
  end
221
183
 
222
- describe ".schema_properties" do
223
- it "lists known properties as symbols" do
224
- klass = described_class["Container"]
225
- props = klass.schema_properties
226
- expect(props).to include(:name, :image, :ports, :env, :resources)
227
- end
184
+ it "resolves EnvVar" do
185
+ sub_spec["EnvVar"].should.be < sub_spec
228
186
  end
229
187
 
230
- describe "#initialize" do
231
- let(:klass) { described_class["Container"] }
188
+ it "resolves ResourceRequirements" do
189
+ sub_spec["ResourceRequirements"].should.be < sub_spec
190
+ end
232
191
 
233
- it "accepts a hash" do
234
- sub = klass.new(name: "app", image: "nginx")
235
- expect(sub.to_h).to include(name: "app", image: "nginx")
236
- end
192
+ it "resolves a full definition key" do
193
+ sub_spec["io.k8s.api.core.v1.Container"].should.be < sub_spec
194
+ end
237
195
 
238
- it "accepts string keys" do
239
- sub = klass.new("name" => "app", "image" => "nginx")
240
- expect(sub.to_h).to include(name: "app", image: "nginx")
241
- end
196
+ it "raises for an unknown definition" do
197
+ error = lambda { sub_spec["ThisDoesNotExist999"] }.should.raise(RuntimeError)
198
+ error.message.should.match(/No definition found/)
199
+ end
200
+ end
242
201
 
243
- it "creates an empty sub-spec when no arguments are given" do
244
- sub = klass.new
245
- expect(sub.to_h).to eq({})
246
- end
202
+ describe ".definition_name" do
203
+ it "returns the short name used to look up the sub-spec" do
204
+ container.().definition_name.should == "Container"
205
+ end
206
+ end
247
207
 
248
- it "accepts a block for DSL-style initialization" do
249
- sub = klass.new {
250
- self.name = "app"
251
- self.image = "nginx:1.27"
252
- }
253
- expect(sub.to_h).to include(name: "app", image: "nginx:1.27")
254
- end
208
+ describe ".schema" do
209
+ it "has a schema attached" do
210
+ container.().schema.should.not.be.nil
211
+ end
212
+ end
255
213
 
256
- it "supports nested DSL" do
257
- sub = klass.new {
258
- self.name = "app"
259
- self.image = "nginx"
260
- self.resources.requests = { cpu: "100m", memory: "128Mi" }
261
- self.resources.limits = { cpu: "500m", memory: "256Mi" }
262
- }
263
- expect(sub.to_h[:resources][:requests]).to eq({ cpu: "100m", memory: "128Mi" })
264
- end
214
+ describe ".schema_properties" do
215
+ it "lists known properties as symbols" do
216
+ props = container.().schema_properties
217
+ [:name, :image, :ports, :env, :resources].each { |prop| props.should.include prop }
218
+ end
219
+ end
265
220
 
266
- it "ignores unknown properties" do
267
- sub = klass.new(name: "app", bogus_field: "ignored")
268
- expect(sub.to_h).to eq({ name: "app" })
269
- end
221
+ describe "#initialize" do
222
+ it "accepts a hash" do
223
+ sub = container.().new(name: "app", image: "nginx")
224
+ sub.to_h[:name].should == "app"
225
+ sub.to_h[:image].should == "nginx"
270
226
  end
271
227
 
272
- describe "accessor methods" do
273
- let(:klass) { described_class["Container"] }
228
+ it "accepts string keys" do
229
+ sub = container.().new("name" => "app", "image" => "nginx")
230
+ sub.to_h[:name].should == "app"
231
+ sub.to_h[:image].should == "nginx"
232
+ end
274
233
 
275
- it "defines reader methods for schema properties" do
276
- sub = klass.new(name: "app", image: "nginx")
277
- expect(sub.name).to eq("app")
278
- expect(sub.image).to eq("nginx")
279
- end
234
+ it "creates an empty sub-spec when no arguments are given" do
235
+ container.().new.to_h.should == {}
236
+ end
280
237
 
281
- it "returns nil for unset properties" do
282
- sub = klass.new(name: "app")
283
- expect(sub.image).to be_nil
284
- end
238
+ it "accepts a block for DSL-style initialization" do
239
+ sub = container.().new {
240
+ self.name = "app"
241
+ self.image = "nginx:1.27"
242
+ }
243
+ sub.to_h[:name].should == "app"
244
+ sub.to_h[:image].should == "nginx:1.27"
285
245
  end
286
246
 
287
- describe "#valid?" do
288
- let(:klass) { described_class["Container"] }
247
+ it "supports nested DSL" do
248
+ sub = container.().new {
249
+ self.name = "app"
250
+ self.image = "nginx"
251
+ self.resources.requests = { cpu: "100m", memory: "128Mi" }
252
+ self.resources.limits = { cpu: "500m", memory: "256Mi" }
253
+ }
254
+ sub.to_h[:resources][:requests].should == { cpu: "100m", memory: "128Mi" }
255
+ end
289
256
 
290
- it "returns true for valid data" do
291
- sub = klass.new(name: "app", image: "nginx")
292
- expect(sub.valid?).to be true
293
- end
257
+ it "ignores unknown properties" do
258
+ container.().new(name: "app", bogus_field: "ignored").to_h.should == { name: "app" }
259
+ end
260
+ end
294
261
 
295
- it "returns false for data violating the schema" do
296
- sub = klass.new(name: "app", ports: "not_an_array")
297
- expect(sub.valid?).to be false
298
- end
262
+ describe "accessor methods" do
263
+ it "defines reader methods for schema properties" do
264
+ sub = container.().new(name: "app", image: "nginx")
265
+ sub.name.should == "app"
266
+ sub.image.should == "nginx"
267
+ end
299
268
 
300
- it "returns false when required fields are missing" do
301
- # Container requires 'name'
302
- sub = klass.new(image: "nginx")
303
- expect(sub.valid?).to be false
304
- end
269
+ it "returns nil for unset properties" do
270
+ container.().new(name: "app").image.should.be.nil
305
271
  end
272
+ end
306
273
 
307
- describe "#valid!" do
308
- let(:klass) { described_class["Container"] }
274
+ describe "#valid?" do
275
+ it "returns true for valid data" do
276
+ container.().new(name: "app", image: "nginx").valid?.should.be.true
277
+ end
309
278
 
310
- it "returns true for valid data" do
311
- sub = klass.new(name: "app")
312
- expect(sub.valid!).to be true
313
- end
279
+ it "returns false for data violating the schema" do
280
+ container.().new(name: "app", ports: "not_an_array").valid?.should.be.false
281
+ end
314
282
 
315
- it "raises ValidationError for invalid data" do
316
- sub = klass.new(image: "nginx")
317
- expect { sub.valid! }.to raise_error(Kube::ValidationError)
318
- end
283
+ it "returns false when required fields are missing" do
284
+ # Container requires 'name'
285
+ container.().new(image: "nginx").valid?.should.be.false
286
+ end
287
+ end
319
288
 
320
- it "includes the definition name in the error" do
321
- sub = klass.new(image: "nginx")
322
- expect { sub.valid! }.to raise_error(Kube::ValidationError, /Container/)
323
- end
289
+ describe "#valid!" do
290
+ it "returns true for valid data" do
291
+ container.().new(name: "app").valid!.should.be.true
292
+ end
324
293
 
325
- it "shows which required keys are missing" do
326
- sub = klass.new(image: "nginx")
327
- expect { sub.valid! }.to raise_error(Kube::ValidationError) do |error|
328
- expect(error.message).to include("name is required but missing")
329
- end
330
- end
294
+ it "raises ValidationError for invalid data" do
295
+ sub = container.().new(image: "nginx")
296
+ lambda { sub.valid! }.should.raise(Kube::ValidationError)
331
297
  end
332
298
 
333
- describe "#to_h" do
334
- let(:klass) { described_class["Container"] }
299
+ it "includes the definition name in the error" do
300
+ sub = container.().new(image: "nginx")
301
+ error = lambda { sub.valid! }.should.raise(Kube::ValidationError)
302
+ error.message.should.match(/Container/)
303
+ end
335
304
 
336
- it "returns a plain Hash" do
337
- sub = klass.new(name: "app", image: "nginx")
338
- h = sub.to_h
339
- expect(h).to be_a(Hash)
340
- expect(h).to eq({ name: "app", image: "nginx" })
341
- end
305
+ it "shows which required keys are missing" do
306
+ sub = container.().new(image: "nginx")
307
+ error = lambda { sub.valid! }.should.raise(Kube::ValidationError)
308
+ error.message.should.include "name is required but missing"
309
+ end
310
+ end
342
311
 
343
- it "strips empty sub-hashes" do
344
- sub = klass.new(name: "app")
345
- expect(sub.to_h).to eq({ name: "app" })
346
- end
312
+ describe "#to_h" do
313
+ it "returns a plain Hash" do
314
+ h = container.().new(name: "app", image: "nginx").to_h
315
+ h.should.be.kind_of Hash
316
+ h.should == { name: "app", image: "nginx" }
317
+ end
347
318
 
348
- it "does NOT include apiVersion or kind" do
349
- sub = klass.new(name: "app")
350
- expect(sub.to_h).not_to have_key(:apiVersion)
351
- expect(sub.to_h).not_to have_key(:kind)
352
- end
319
+ it "strips empty sub-hashes" do
320
+ container.().new(name: "app").to_h.should == { name: "app" }
321
+ end
353
322
 
354
- it "preserves nested structure" do
355
- sub = klass.new {
356
- self.name = "app"
357
- self.image = "nginx"
358
- self.ports = [{ containerPort: 80 }]
359
- }
360
- expect(sub.to_h[:ports]).to eq([{ containerPort: 80 }])
361
- end
323
+ it "does NOT include apiVersion or kind" do
324
+ h = container.().new(name: "app").to_h
325
+ h.should.not.include :apiVersion
326
+ h.should.not.include :kind
362
327
  end
363
328
 
364
- describe "#==" do
365
- let(:klass) { described_class["Container"] }
329
+ it "preserves nested structure" do
330
+ sub = container.().new {
331
+ self.name = "app"
332
+ self.image = "nginx"
333
+ self.ports = [{ containerPort: 80 }]
334
+ }
335
+ sub.to_h[:ports].should == [{ containerPort: 80 }]
336
+ end
337
+ end
366
338
 
367
- it "considers two sub-specs equal when their data matches" do
368
- a = klass.new(name: "app", image: "nginx")
369
- b = klass.new(name: "app", image: "nginx")
370
- expect(a).to eq(b)
371
- end
339
+ describe "#==" do
340
+ it "considers two sub-specs equal when their data matches" do
341
+ a = container.().new(name: "app", image: "nginx")
342
+ b = container.().new(name: "app", image: "nginx")
343
+ a.should == b
344
+ end
372
345
 
373
- it "considers two sub-specs unequal when their data differs" do
374
- a = klass.new(name: "app", image: "nginx")
375
- b = klass.new(name: "other", image: "nginx")
376
- expect(a).not_to eq(b)
377
- end
346
+ it "considers two sub-specs unequal when their data differs" do
347
+ a = container.().new(name: "app", image: "nginx")
348
+ b = container.().new(name: "other", image: "nginx")
349
+ a.should.not == b
350
+ end
378
351
 
379
- it "is not equal to a plain Hash" do
380
- sub = klass.new(name: "app")
381
- expect(sub).not_to eq({ name: "app" })
382
- end
352
+ it "is not equal to a plain Hash" do
353
+ container.().new(name: "app").should.not == { name: "app" }
383
354
  end
355
+ end
384
356
 
385
- describe "auto-coercion in Resource" do
386
- it "auto-coerces SubSpec instances inside Resource arrays" do
387
- container = described_class["Container"].new {
388
- self.name = "app"
389
- self.image = "nginx:1.27"
390
- self.ports = [{ containerPort: 80 }]
391
- }
392
-
393
- deploy = Kube::Schema["Deployment"].new {
394
- metadata.name = "web"
395
- spec.replicas = 1
396
- spec.selector.matchLabels = { app: "web" }
397
- spec.template.metadata.labels = { app: "web" }
398
- spec.template.spec.containers = [container]
399
- }
400
-
401
- h = deploy.to_h
402
- containers = h[:spec][:template][:spec][:containers]
403
- expect(containers).to be_an(Array)
404
- expect(containers.first).to be_a(Hash)
405
- expect(containers.first[:name]).to eq("app")
406
- expect(containers.first[:image]).to eq("nginx:1.27")
407
- end
357
+ describe "auto-coercion in Resource" do
358
+ it "auto-coerces SubSpec instances inside Resource arrays" do
359
+ app = container.().new {
360
+ self.name = "app"
361
+ self.image = "nginx:1.27"
362
+ self.ports = [{ containerPort: 80 }]
363
+ }
364
+
365
+ deploy = Kube::Schema["Deployment"].new {
366
+ metadata.name = "web"
367
+ spec.replicas = 1
368
+ spec.selector.matchLabels = { app: "web" }
369
+ spec.template.metadata.labels = { app: "web" }
370
+ spec.template.spec.containers = [app]
371
+ }
372
+
373
+ containers = deploy.to_h[:spec][:template][:spec][:containers]
374
+ containers.should.be.kind_of Array
375
+ containers.first.should.be.kind_of Hash
376
+ containers.first[:name].should == "app"
377
+ containers.first[:image].should == "nginx:1.27"
378
+ end
408
379
 
409
- it "produces valid YAML with auto-coerced SubSpec" do
410
- container = described_class["Container"].new {
411
- self.name = "nginx"
412
- self.image = "nginx:1.27"
413
- self.ports = [{ containerPort: 80 }]
414
- }
415
-
416
- deploy = Kube::Schema["Deployment"].new {
417
- metadata.name = "web"
418
- spec.replicas = 1
419
- spec.selector.matchLabels = { app: "web" }
420
- spec.template.metadata.labels = { app: "web" }
421
- spec.template.spec.containers = [container]
422
- }
423
-
424
- yaml = deploy.to_yaml
425
- parsed = YAML.safe_load(yaml)
426
- expect(parsed["spec"]["template"]["spec"]["containers"].first["name"]).to eq("nginx")
427
- end
380
+ it "produces valid YAML with auto-coerced SubSpec" do
381
+ nginx = container.().new {
382
+ self.name = "nginx"
383
+ self.image = "nginx:1.27"
384
+ self.ports = [{ containerPort: 80 }]
385
+ }
386
+
387
+ deploy = Kube::Schema["Deployment"].new {
388
+ metadata.name = "web"
389
+ spec.replicas = 1
390
+ spec.selector.matchLabels = { app: "web" }
391
+ spec.template.metadata.labels = { app: "web" }
392
+ spec.template.spec.containers = [nginx]
393
+ }
394
+
395
+ parsed = YAML.safe_load(deploy.to_yaml)
396
+ parsed["spec"]["template"]["spec"]["containers"].first["name"].should == "nginx"
397
+ end
428
398
 
429
- it "handles multiple SubSpec instances in an array" do
430
- app = described_class["Container"].new(name: "app", image: "app:latest")
431
- sidecar = described_class["Container"].new(name: "sidecar", image: "sidecar:latest")
432
-
433
- deploy = Kube::Schema["Deployment"].new {
434
- metadata.name = "web"
435
- spec.replicas = 1
436
- spec.selector.matchLabels = { app: "web" }
437
- spec.template.metadata.labels = { app: "web" }
438
- spec.template.spec.containers = [app, sidecar]
439
- }
440
-
441
- containers = deploy.to_h[:spec][:template][:spec][:containers]
442
- expect(containers.size).to eq(2)
443
- expect(containers.map { |c| c[:name] }).to eq(["app", "sidecar"])
444
- end
399
+ it "handles multiple SubSpec instances in an array" do
400
+ app = container.().new(name: "app", image: "app:latest")
401
+ sidecar = container.().new(name: "sidecar", image: "sidecar:latest")
402
+
403
+ deploy = Kube::Schema["Deployment"].new {
404
+ metadata.name = "web"
405
+ spec.replicas = 1
406
+ spec.selector.matchLabels = { app: "web" }
407
+ spec.template.metadata.labels = { app: "web" }
408
+ spec.template.spec.containers = [app, sidecar]
409
+ }
410
+
411
+ containers = deploy.to_h[:spec][:template][:spec][:containers]
412
+ containers.size.should == 2
413
+ containers.map { |c| c[:name] }.should == ["app", "sidecar"]
414
+ end
445
415
 
446
- it "works mixed with plain hashes" do
447
- container = described_class["Container"].new(name: "typed", image: "typed:latest")
448
-
449
- deploy = Kube::Schema["Deployment"].new {
450
- metadata.name = "web"
451
- spec.replicas = 1
452
- spec.selector.matchLabels = { app: "web" }
453
- spec.template.metadata.labels = { app: "web" }
454
- spec.template.spec.containers = [
455
- container,
456
- { name: "plain", image: "plain:latest" }
457
- ]
458
- }
459
-
460
- containers = deploy.to_h[:spec][:template][:spec][:containers]
461
- expect(containers.map { |c| c[:name] }).to eq(["typed", "plain"])
462
- end
416
+ it "works mixed with plain hashes" do
417
+ typed = container.().new(name: "typed", image: "typed:latest")
418
+
419
+ deploy = Kube::Schema["Deployment"].new {
420
+ metadata.name = "web"
421
+ spec.replicas = 1
422
+ spec.selector.matchLabels = { app: "web" }
423
+ spec.template.metadata.labels = { app: "web" }
424
+ spec.template.spec.containers = [
425
+ typed,
426
+ { name: "plain", image: "plain:latest" }
427
+ ]
428
+ }
429
+
430
+ containers = deploy.to_h[:spec][:template][:spec][:containers]
431
+ containers.map { |c| c[:name] }.should == ["typed", "plain"]
463
432
  end
433
+ end
464
434
 
465
- describe "disambiguation" do
466
- it "prefers stable API versions over beta/alpha" do
467
- # MatchCondition exists in v1, v1alpha1, and v1beta1
468
- klass = described_class["MatchCondition"]
469
- expect(klass).to be < described_class
470
- expect(klass.schema).not_to be_nil
471
- end
435
+ describe "disambiguation" do
436
+ it "prefers stable API versions over beta/alpha" do
437
+ # MatchCondition exists in v1, v1alpha1, and v1beta1
438
+ klass = sub_spec["MatchCondition"]
439
+ klass.should.be < sub_spec
440
+ klass.schema.should.not.be.nil
472
441
  end
442
+ end
473
443
 
474
- describe "Instance#list_definitions" do
475
- it "returns a sorted array of short definition names" do
476
- instance = Kube::Schema::Instance.new("1.34")
477
- defs = instance.list_definitions
478
- expect(defs).to be_an(Array)
479
- expect(defs).not_to be_empty
480
- expect(defs).to include("Container", "ContainerPort", "Probe", "Volume")
481
- expect(defs).to eq(defs.sort)
482
- end
444
+ describe "Instance#list_definitions" do
445
+ it "returns a sorted array of short definition names" do
446
+ defs = Kube::Schema::Instance.new("1.34").list_definitions
447
+ defs.should.be.kind_of Array
448
+ defs.should.not.be.empty
449
+ ["Container", "ContainerPort", "Probe", "Volume"].each { |name| defs.should.include name }
450
+ defs.should == defs.sort
483
451
  end
484
452
  end
485
453
  end