kerbi 0.0.1 → 0.0.2

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cli/base_handler.rb +180 -0
  3. data/lib/cli/base_serializer.rb +120 -0
  4. data/lib/cli/config_handler.rb +51 -0
  5. data/lib/cli/entry_serializers.rb +99 -0
  6. data/lib/cli/project_handler.rb +2 -2
  7. data/lib/cli/root_handler.rb +32 -13
  8. data/lib/cli/state_handler.rb +95 -0
  9. data/lib/cli/values_handler.rb +4 -3
  10. data/lib/config/cli_schema.rb +299 -27
  11. data/lib/config/config_file.rb +60 -0
  12. data/lib/config/globals.rb +4 -0
  13. data/lib/config/run_opts.rb +150 -0
  14. data/lib/config/state_consts.rb +10 -0
  15. data/lib/kerbi.rb +31 -9
  16. data/lib/main/errors.rb +109 -0
  17. data/lib/main/mixer.rb +12 -8
  18. data/lib/mixins/cli_state_helpers.rb +136 -0
  19. data/lib/mixins/cm_backend_testing.rb +95 -0
  20. data/lib/mixins/entry_tag_logic.rb +183 -0
  21. data/lib/state/base_backend.rb +59 -0
  22. data/lib/state/config_map_backend.rb +119 -0
  23. data/lib/state/entry.rb +173 -0
  24. data/lib/state/entry_set.rb +137 -0
  25. data/lib/state/metadata.yaml.erb +11 -0
  26. data/lib/state/mixers.rb +23 -0
  27. data/lib/state/resources.yaml.erb +17 -0
  28. data/lib/utils/cli.rb +77 -10
  29. data/lib/utils/helm.rb +10 -12
  30. data/lib/utils/k8s_auth.rb +87 -0
  31. data/lib/utils/misc.rb +36 -1
  32. data/lib/utils/mixing.rb +1 -1
  33. data/lib/utils/values.rb +13 -22
  34. data/spec/cli/config_handler_spec.rb +38 -0
  35. data/spec/cli/root_handler_spec.rb +99 -0
  36. data/spec/cli/state_handler_spec.rb +139 -0
  37. data/spec/cli/values_handler_spec.rb +17 -0
  38. data/spec/expectations/common/bad-tag.txt +1 -0
  39. data/spec/expectations/config/bad-set.txt +1 -0
  40. data/spec/expectations/config/set.txt +1 -0
  41. data/spec/expectations/config/show-default.yaml +6 -0
  42. data/spec/expectations/root/template-inlines.yaml +31 -0
  43. data/spec/expectations/root/template-production.yaml +31 -0
  44. data/spec/expectations/root/template-read-inlines.yaml +31 -0
  45. data/spec/expectations/root/template-read.yaml +31 -0
  46. data/spec/expectations/root/template-write.yaml +31 -0
  47. data/spec/expectations/root/template.yaml +31 -0
  48. data/spec/expectations/root/values.json +28 -0
  49. data/spec/expectations/state/delete.txt +1 -0
  50. data/spec/expectations/state/demote.txt +1 -0
  51. data/spec/expectations/state/init-already-existed.txt +2 -0
  52. data/spec/expectations/state/init-both-created.txt +2 -0
  53. data/spec/expectations/state/list.json +51 -0
  54. data/spec/expectations/state/list.txt +6 -0
  55. data/spec/expectations/state/list.yaml +35 -0
  56. data/spec/expectations/state/promote.txt +1 -0
  57. data/spec/expectations/state/prune-candidates.txt +1 -0
  58. data/spec/expectations/state/retag.txt +1 -0
  59. data/spec/expectations/state/set.txt +1 -0
  60. data/spec/expectations/state/show.json +13 -0
  61. data/spec/expectations/state/show.txt +13 -0
  62. data/spec/expectations/state/show.yaml +8 -0
  63. data/spec/expectations/state/status-all-working.txt +4 -0
  64. data/spec/expectations/state/status-not-provisioned.txt +4 -0
  65. data/spec/expectations/values/order-of-precedence.yaml +4 -0
  66. data/spec/main/configmap_backend_spec.rb +109 -0
  67. data/spec/main/state_entry_set_spec.rb +112 -0
  68. data/spec/main/state_entry_spec.rb +109 -0
  69. data/spec/spec_helper.rb +87 -1
  70. data/spec/utils/helm_spec.rb +1 -21
  71. data/spec/utils/k8s_auth_spec.rb +32 -0
  72. data/spec/utils/misc_utils_spec.rb +9 -0
  73. data/spec/utils/values_utils_spec.rb +12 -19
  74. metadata +114 -13
  75. data/lib/cli/base.rb +0 -83
  76. data/lib/config/cli_opts.rb +0 -50
  77. data/lib/config/manager.rb +0 -36
  78. data/lib/main/state_manager.rb +0 -47
  79. data/lib/utils/kubectl.rb +0 -58
  80. data/spec/main/examples_spec.rb +0 -12
  81. data/spec/main/state_manager_spec.rb +0 -84
  82. data/spec/utils/state_utils.rb +0 -15
@@ -0,0 +1,31 @@
1
+ apiVersion: v1
2
+ kind: Pod
3
+ metadata:
4
+ name: hello-kerbi
5
+ namespace: foo
6
+ annotations:
7
+ author: xavier
8
+ labels:
9
+ app: hello-kerbi
10
+ spec:
11
+ containers:
12
+ - name: main
13
+ image: nginx:alpine
14
+
15
+ ---
16
+
17
+ apiVersion: v1
18
+ kind: Service
19
+ metadata:
20
+ name: hello-kerbi
21
+ namespace: foo
22
+ annotations:
23
+ author: xavier
24
+ labels:
25
+ app: hello-kerbi
26
+ spec:
27
+ type: ClusterIP
28
+ selector:
29
+ app: hello-kerbi
30
+ ports:
31
+ - port: 80
@@ -0,0 +1,28 @@
1
+ {
2
+ "centos": {
3
+ "pod": {
4
+ "image": "centos"
5
+ },
6
+ "service": {
7
+ "type": "ClusterIP"
8
+ }
9
+ },
10
+
11
+ "nginx": {
12
+ "pod": {
13
+ "image": "nginx"
14
+ },
15
+ "service": {
16
+ "type": "ClusterIP"
17
+ }
18
+ },
19
+
20
+ "debian": {
21
+ "pod": {
22
+ "image": "debian"
23
+ },
24
+ "service": {
25
+ "type": "ClusterIP"
26
+ }
27
+ }
28
+ }
@@ -0,0 +1 @@
1
+ Deleted state[two]. Remaining entries: 3
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[[cand]-two].tag from two => [cand]-two\e[0m
@@ -0,0 +1,2 @@
1
+ \e[1;39;49mnamespaces/kerbi-spec: \e[0m\e[1;32;49mAlready existed\e[0m
2
+ \e[1;39;49mkerbi-spec/configmaps/kerbi-state-tracker: \e[0m\e[1;32;49mAlready existed\e[0m
@@ -0,0 +1,2 @@
1
+ \e[1;39;49mnamespaces/kerbi-spec: \e[0m\e[1;34;49mCreated\e[0m
2
+ \e[1;39;49mkerbi-spec/configmaps/kerbi-state-tracker: \e[0m\e[1;34;49mCreated\e[0m
@@ -0,0 +1,51 @@
1
+ [
2
+ {
3
+ "tag": "[cand]-four",
4
+ "message": null,
5
+ "created_at": "2003-01-01 00:00:00 +0000",
6
+ "values": {
7
+ },
8
+ "default_values": {
9
+ },
10
+ "overridden_keys": [
11
+
12
+ ]
13
+ },
14
+ {
15
+ "tag": "[cand]-three",
16
+ "message": null,
17
+ "created_at": "2002-01-01 00:00:00 +0000",
18
+ "values": {
19
+ },
20
+ "default_values": {
21
+ },
22
+ "overridden_keys": [
23
+
24
+ ]
25
+ },
26
+ {
27
+ "tag": "two",
28
+ "message": "message",
29
+ "created_at": "2001-01-01 00:00:00 +0000",
30
+ "values": {
31
+ },
32
+ "default_values": {
33
+ },
34
+ "overridden_keys": [
35
+
36
+ ]
37
+ },
38
+ {
39
+ "tag": "one",
40
+ "message": null,
41
+ "created_at": "2000-01-01 00:00:00 +0000",
42
+ "values": {
43
+ "x": "x"
44
+ },
45
+ "default_values": {
46
+ },
47
+ "overridden_keys": [
48
+ "x"
49
+ ]
50
+ }
51
+ ]
@@ -0,0 +1,6 @@
1
+ TAG MESSAGE ASSIGNMENTS OVERRIDES CREATED_AT
2
+
3
+ \e[0;33;49m[cand]-four\e[0m 0 0 2003-01-01 00:00:00 +0000
4
+ \e[0;33;49m[cand]-three\e[0m 0 0 2002-01-01 00:00:00 +0000
5
+ \e[0;34;49mtwo\e[0m message 0 0 2001-01-01 00:00:00 +0000
6
+ \e[0;34;49mone\e[0m 1 1 2000-01-01 00:00:00 +0000
@@ -0,0 +1,35 @@
1
+ tag: "[cand]-four"
2
+ message:
3
+ created_at: 2003-01-01 00:00:00.000000000 +00:00
4
+ values: {}
5
+ default_values: {}
6
+ overridden_keys: []
7
+
8
+ ---
9
+
10
+ tag: "[cand]-three"
11
+ message:
12
+ created_at: 2002-01-01 00:00:00.000000000 +00:00
13
+ values: {}
14
+ default_values: {}
15
+ overridden_keys: []
16
+
17
+ ---
18
+
19
+ tag: two
20
+ message: message
21
+ created_at: 2001-01-01 00:00:00.000000000 +00:00
22
+ values: {}
23
+ default_values: {}
24
+ overridden_keys: []
25
+
26
+ ---
27
+
28
+ tag: one
29
+ message:
30
+ created_at: 2000-01-01 00:00:00.000000000 +00:00
31
+ values:
32
+ x: x
33
+ default_values: {}
34
+ overridden_keys:
35
+ - x
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[four].tag from [cand]-four => four\e[0m
@@ -0,0 +1 @@
1
+ Pruned 2 state entries
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[born-again].tag from two => born-again\e[0m
@@ -0,0 +1 @@
1
+ \e[0;32;49mUpdated state[two].message from message => new message\e[0m
@@ -0,0 +1,13 @@
1
+ {
2
+ "tag": "one",
3
+ "message": null,
4
+ "created_at": "2000-01-01 00:00:00 +0000",
5
+ "values": {
6
+ "x": "x"
7
+ },
8
+ "default_values": {
9
+ },
10
+ "overridden_keys": [
11
+ "x"
12
+ ]
13
+ }
@@ -0,0 +1,13 @@
1
+ --------------------------------------------
2
+ \e[1;39;49mTAG\e[0m \e[1;34;49mone\e[0m
3
+ --------------------------------------------
4
+ \e[1;39;49mMESSAGE\e[0m
5
+ --------------------------------------------
6
+ \e[1;39;49mCREATED_AT\e[0m 2000-01-01 00:00:00 +0000
7
+ --------------------------------------------
8
+ \e[1;39;49mVALUES\e[0m x: x
9
+ --------------------------------------------
10
+ \e[1;39;49mDEFAULT_VALUES\e[0m {}
11
+ --------------------------------------------
12
+ \e[1;39;49mOVERRIDDEN_KEYS\e[0m x
13
+ --------------------------------------------
@@ -0,0 +1,8 @@
1
+ tag: one
2
+ message:
3
+ created_at: 2000-01-01 00:00:00.000000000 +00:00
4
+ values:
5
+ x: x
6
+ default_values: {}
7
+ overridden_keys:
8
+ - x
@@ -0,0 +1,4 @@
1
+ \e[1;39;49m1. Create Kubernetes client: \e[0m\e[1;32;49mSuccess\e[0m
2
+ \e[1;39;49m2. List cluster namespaces: \e[0m\e[1;32;49mSuccess\e[0m
3
+ \e[1;39;49m3. Target namespace kerbi-spec exists: \e[0m\e[1;32;49mSuccess\e[0m
4
+ \e[1;39;49m4. Resource kerbi-spec/cm/kerbi-state-tracker exists: \e[0m\e[1;32;49mSuccess\e[0m
@@ -0,0 +1,4 @@
1
+ \e[1;39;49m1. Create Kubernetes client: \e[0m\e[1;32;49mSuccess\e[0m
2
+ \e[1;39;49m2. List cluster namespaces: \e[0m\e[1;32;49mSuccess\e[0m
3
+ \e[1;39;49m3. Target namespace kerbi-spec exists: \e[0m\e[1;31;49mFailure\e[0m
4
+ \e[1;39;49m4. Resource kerbi-spec/cm/kerbi-state-tracker exists: \e[0m\e[1;31;49mFailure\e[0m
@@ -0,0 +1,4 @@
1
+ pod:
2
+ image: nginx:1.20
3
+ service:
4
+ type: NodePort
@@ -0,0 +1,109 @@
1
+ require_relative './../spec_helper'
2
+
3
+ RSpec.describe Kerbi::State::ConfigMapBackend do
4
+
5
+ let(:namespace) { "kerbi-spec" }
6
+ let(:cm_name) { Kerbi::State::Consts::RESOURCE_NAME }
7
+
8
+ before :each do
9
+ kmd("create ns #{namespace}")
10
+ kmd("delete cm #{cm_name} -n #{namespace}")
11
+ # sleep(2) #ADD ME BACK IF WEIRD ERRORS... :/
12
+ end
13
+
14
+ describe "#provision_missing_resources" do
15
+ let(:backend) { make_backend(namespace) }
16
+
17
+ context "when the namespace does not exist" do
18
+ it "provisions accordingly" do
19
+ kmd("delete ns #{namespace}")
20
+ expect(backend.read_write_ready?).to be_falsey
21
+ backend.provision_missing_resources
22
+ end
23
+ end
24
+
25
+ context "when the namespace does exist" do
26
+ before :each do
27
+ kmd("create ns #{namespace}")
28
+ expect(backend.read_write_ready?).to be_falsey
29
+ end
30
+
31
+ context "when the configmap does not exist" do
32
+ it "provisions accordingly" do
33
+ backend.provision_missing_resources
34
+ kmd("delete cm #{cm_name} -n #{namespace}")
35
+ backend.provision_missing_resources
36
+ end
37
+ end
38
+
39
+ context "when the configmap does exist" do
40
+ it "provisions accordingly" do
41
+ backend.provision_missing_resources
42
+ backend.provision_missing_resources
43
+ end
44
+ end
45
+ end
46
+
47
+ after :each do
48
+ expect(backend.read_write_ready?).to eq(true)
49
+ expect(backend.namespace_exists?).to eq(true)
50
+ expect(backend.resource_exists?).to eq(true)
51
+ end
52
+ end
53
+
54
+ describe "#template_resource" do
55
+ context "with 0 entries" do
56
+ it "outputs a descriptor with the right basic properties" do
57
+ result = make_backend("xyz").template_resource([])
58
+ expect(result[:kind]).to eq('ConfigMap')
59
+ expect(result[:metadata][:name]).to eq('kerbi-state-tracker')
60
+ expect(result[:metadata][:namespace]).to eq('xyz')
61
+ expect(result[:data][:entries]).to eq("[]")
62
+ end
63
+ end
64
+
65
+ context "with some entries (for puts only, uncomment)" do
66
+ it "puts it" do
67
+ # entry = new_state("1", created_at: "2022-01-01T00:00:00+00:00")
68
+ # puts entry.to_h
69
+ # result = make_backend("xyz").template_resource([entry])
70
+ # puts result
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "#namespace_exists?" do
76
+ context "when the namespace exists" do
77
+ it "returns true" do
78
+ expect(make_backend("default").namespace_exists?).to be_truthy
79
+ end
80
+ end
81
+ context "when the namespace does not exist" do
82
+ it "returns false" do
83
+ expect(make_backend("nope").namespace_exists?).to be_falsey
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "#apply_resource and #read_entries" do
89
+ let(:entries) do
90
+ [
91
+ new_state("one", message: "m-one", created_at: "2022-01-01T00:00:00+00:00"),
92
+ new_state("two", message: "m-two", created_at: "2022-02-01T00:00:00+00:00"),
93
+ ]
94
+ end
95
+
96
+ it "creates a configmap with the right contents" do
97
+ subject = make_backend(namespace)
98
+ descriptor = subject.template_resource(entries)
99
+ subject.apply_resource(descriptor)
100
+ sleep(1)
101
+ actual = subject.send(:read_entries)
102
+ expect(actual.count).to eq(2)
103
+
104
+ actual_one = actual[0].values_at("tag", "message", "created_at")
105
+ expected_one = entries[0].to_h.values_at(:tag, :message, :created_at)
106
+ expect(actual_one).to eq(expected_one)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,112 @@
1
+ require_relative './../spec_helper'
2
+
3
+ RSpec.describe Kerbi::State::EntrySet do
4
+
5
+ let(:set) do
6
+ new_state_set(
7
+ one: { created_at: Time.new(2000).to_s },
8
+ two: { created_at: Time.new(2001).to_s },
9
+ "[cand]-one".to_sym => { created_at: Time.new(2002).to_s },
10
+ "[cand]-two".to_sym => { created_at: Time.new(2003).to_s }
11
+ )
12
+ end
13
+
14
+ let(:bad_set) do
15
+ new_state_set(
16
+ "".to_sym => { },
17
+ )
18
+ end
19
+
20
+ describe "#initialize" do
21
+ it "sorts DESC on created_at" do
22
+ expect(set.entries[0].tag).to eq("[cand]-two")
23
+ end
24
+ end
25
+
26
+ describe "validate!" do
27
+ context "when there are no errors" do
28
+ it "does not raise an error" do
29
+ set.validate!
30
+ end
31
+ end
32
+
33
+ context "when there are errors" do
34
+ it "raises the right error" do
35
+ expect{
36
+ bad_set.validate!
37
+ }.to raise_exception(Kerbi::EntryValidationError)
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#latest" do
43
+ it "returns the correct entry" do
44
+ expect(set.latest.tag).to eq("two")
45
+ end
46
+ end
47
+
48
+ describe "#latest_candidate" do
49
+ it "returns the correct entry" do
50
+ expect(set.latest_candidate.tag).to eq("[cand]-two")
51
+ end
52
+ end
53
+
54
+ describe "#candidates" do
55
+ it "returns the right entries" do
56
+ expected = %w[[cand]-two [cand]-one]
57
+ expect(set.candidates.map(&:tag)).to eq(expected)
58
+ end
59
+ end
60
+
61
+ describe "#committed" do
62
+ it "returns the right entries" do
63
+ expected = %w[two one]
64
+ expect(set.committed.map(&:tag)).to eq(expected)
65
+ end
66
+ end
67
+
68
+ describe "#find_entry_for_read" do
69
+ context "when the substitutions work and the entry exists" do
70
+ it "returns the right entry" do
71
+ actual = set.find_entry_for_read("two")
72
+ expect(actual.tag).to eq("two")
73
+
74
+ actual = set.find_entry_for_read("@latest")
75
+ expect(actual.tag).to eq("two")
76
+
77
+ actual = set.find_entry_for_read("@candidate")
78
+ expect(actual.tag).to eq("[cand]-two")
79
+ end
80
+ end
81
+
82
+ context "when either the resolution fails or the entry does not exist" do
83
+ it "raises Kerbi::StateNotFoundError" do
84
+ expect {
85
+ set.find_entry_for_read("three")
86
+ }.to raise_exception(Kerbi::StateNotFoundError)
87
+
88
+ expect {
89
+ set.find_entry_for_read("not-@latest")
90
+ }.to raise_exception(Kerbi::StateNotFoundError)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#find_or_init_entry_for_write" do
96
+ it "returns the right entry" do
97
+ actual = set.find_or_init_entry_for_write("two")
98
+ expect(actual.tag).to eq("two")
99
+
100
+ actual = set.find_or_init_entry_for_write("@latest")
101
+ expect(actual.tag).to eq("two")
102
+
103
+ actual = set.find_or_init_entry_for_write("@candidate")
104
+ expect(actual.tag).to eq("[cand]-two")
105
+
106
+ actual = set.find_or_init_entry_for_write("@new-candidate")
107
+ expect(actual.tag).to_not eq("[cand]-two")
108
+ expect(actual.tag).to_not be_falsey
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,109 @@
1
+ require_relative './../spec_helper'
2
+
3
+ RSpec.describe Kerbi::State::Entry do
4
+
5
+ let(:subject_cls) { Kerbi::State::Entry }
6
+ let(:cand_prefix) { subject_cls::CANDIDATE_PREFIX }
7
+
8
+ let(:default_dict) do
9
+ {
10
+ tag: "tag",
11
+ message: "message",
12
+ values: {x: {y: "z"}},
13
+ default_values: {y: "z"},
14
+ created_at: "2020-01-02T03:04:00",
15
+ }
16
+ end
17
+
18
+ describe "#candiate? and #committed?" do
19
+ context "when it is a candidate" do
20
+ it "returns true for #candidate and false for #committed" do
21
+ expect(new_state("[cand]-one").candidate?).to be_truthy
22
+ expect(new_state("[cand]-one").committed?).to be_falsey
23
+ end
24
+ end
25
+ context "when it is a candidate" do
26
+ it "returns false for #candidate and true for #committed" do
27
+ expect(new_state("[cant]-one").candidate?).to be_falsey
28
+ expect(new_state("[cant]-one").committed?).to be_truthy
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#validate" do
34
+ context "when there is a tag error" do
35
+ it "finds validation errors" do
36
+ (state = new_state("")).validate
37
+ expect(state.valid?).to be_falsey
38
+
39
+ (state = new_state(" ")).validate
40
+ expect(state.valid?).to be_falsey
41
+ end
42
+ end
43
+
44
+ context "when there are zero tag errors" do
45
+ it "finds validation errors" do
46
+ (state = new_state("a")).validate
47
+ expect(state.valid?).to be_truthy
48
+
49
+ (state = new_state("|")).validate
50
+ expect(state.valid?).to be_truthy
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "#promote" do
56
+ context "when the entry is a candidate" do
57
+ it "removes the [cand]- flag" do
58
+ old = (state = new_state("#{cand_prefix}foo")).promote
59
+ expect(state.tag).to eq("foo")
60
+ expect(old).to eq("#{cand_prefix}foo")
61
+ end
62
+ end
63
+
64
+ context "when the entry is not a candidate" do
65
+ it "raises" do
66
+ expect {
67
+ new_state("foo").promote
68
+ }.to raise_exception(Kerbi::StateNotPromotable)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#demote" do
74
+ context "when the entry is committed" do
75
+ it "adds the [cand]- flag" do
76
+ old = (state = new_state("foo")).demote
77
+ expect(state.tag).to eq("#{cand_prefix}foo")
78
+ expect(old).to eq("foo")
79
+ end
80
+ end
81
+
82
+ context "when the entry is not a candidate" do
83
+ it "raises" do
84
+ expect {
85
+ new_state("#{cand_prefix}foo").demote
86
+ }.to raise_exception(Kerbi::StateNotDemotable)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe ".from_dict" do
92
+ it "parses the created_at timestamp correctly" do
93
+ entry = subject_cls.from_dict(nil, default_dict)
94
+ expected = Time.new(2020, 1, 2, 3, 4, 0)
95
+ expect(entry.created_at).to eq(expected)
96
+ end
97
+ end
98
+
99
+ describe "#to_h" do
100
+ it "returns the right dict" do
101
+ entry = new_state("foo", default_dict)
102
+ actual = entry.to_h
103
+ actual.delete(:created_at)
104
+ expect = default_dict.deep_dup
105
+ expect.delete(:created_at)
106
+ expect(actual).to eq(expect)
107
+ end
108
+ end
109
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,93 @@ SimpleCov.start
5
5
 
6
6
  require_relative './../lib/kerbi'
7
7
 
8
+ def kmd(command)
9
+ opts = { err: File::NULL, out: File::NULL }
10
+ system("kubectl #{command} --context kind-kind", **opts)
11
+ end
12
+
13
+ # @return [Kerbi::State::ConfigMapBackend]
14
+ def make_backend(namespace)
15
+ Kerbi::State::ConfigMapBackend.new(
16
+ Kerbi::Utils::K8sAuth.kube_config_bundle,
17
+ namespace
18
+ )
19
+ end
20
+
21
+ def new_state(tag, dict={})
22
+ set = dict.delete(:state)
23
+ dict[:tag] = tag
24
+ Kerbi::State::Entry.from_dict(set, dict)
25
+ end
26
+
27
+ def new_state_set(bundles)
28
+ dicts = bundles.map { |kv| { tag: kv[0].to_s, **kv[1] } }
29
+ Kerbi::State::EntrySet.new(dicts)
30
+ end
31
+
32
+ def cli(command, escaped: false)
33
+ $stdout = StringIO.new
34
+ begin
35
+ command = command.split(" ") if command.is_a?(String)
36
+ Kerbi::Cli::RootHandler.start(command)
37
+ output = $stdout.string
38
+ $stdout = STDOUT
39
+ escaped ? output.gsub("\e", "\\e") : output
40
+ ensure
41
+ $stdout = STDOUT
42
+ end
43
+ end
44
+
45
+ def load_exp_file(dir, file, ext)
46
+ path = "#{__dir__}/expectations/#{dir}/#{file}.#{ext}"
47
+ File.read(path)
48
+ end
49
+
50
+ def read_exp_file(dir, file, ext)
51
+ expected_str = load_exp_file(dir, file, ext)
52
+ if ext == 'json'
53
+ JSON.parse(expected_str)
54
+ elsif ext == 'yaml'
55
+ YAML.load_stream(expected_str)
56
+ else
57
+ expected_str.gsub(/\s+/, "")
58
+ end
59
+ end
60
+
61
+ def exp_cli_eq_file(cmd, dir, file, ext='txt')
62
+ actual_str = cli(cmd)
63
+ expected = read_exp_file(dir, file, ext)
64
+
65
+ if ext == 'json'
66
+ expect(JSON.parse(actual_str)).to eq(expected)
67
+ elsif ext == 'yaml'
68
+ actual = YAML.load_stream(actual_str)
69
+ expect(actual).to eq(expected)
70
+ else
71
+ actual = actual_str.gsub(/\s+/, "").gsub("\e", "\\e")
72
+ expect(actual).to eq(expected)
73
+ end
74
+ end
75
+
76
+ def hello_kerbi(cmd, namespace=nil)
77
+ target = "#{__dir__}/../examples/hello-kerbi"
78
+ cmd = "#{cmd} --project-root #{target}"
79
+ cmd = "#{cmd} --namespace #{namespace}" if namespace
80
+ cmd
81
+ end
82
+
83
+ def cmd_group_spec(cmd, dir, file, opts={})
84
+ (opts[:formats] || %w[yaml json table]).each do |format|
85
+ context "with --output-format #{format} #{opts[:context_append]}" do
86
+ it "echos the expected text" do
87
+ extension = format == 'table' ? "txt" : format
88
+ cmd_with_fmt = "#{cmd} -o #{format}"
89
+ exp_cli_eq_file(cmd_with_fmt, dir, file, extension)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
8
95
  module Kerbi
9
96
  module Testing
10
97
 
@@ -33,7 +120,6 @@ module Kerbi
33
120
  system "rm -rf #{TEST_YAMLS_DIR}"
34
121
  system "mkdir #{TEST_YAMLS_DIR}"
35
122
  end
36
-
37
123
  end
38
124
  end
39
125