codify-plugin-lib 1.0.37 → 1.0.39

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,63 +1,54 @@
1
1
  import { Resource } from './resource.js';
2
- import { ParameterOperation, ResourceConfig, ResourceOperation } from 'codify-schemas';
3
- import { ChangeSet, ParameterChange } from './change-set.js';
2
+ import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
4
3
  import { spy } from 'sinon';
5
4
  import { Plan } from './plan.js';
6
- import { StatefulParameter } from './stateful-parameter.js';
7
5
  import { describe, expect, it } from 'vitest'
6
+ import { ResourceConfiguration, ValidationResult } from './resource-types.js';
8
7
 
9
- class TestResource extends Resource<TestConfig> {
10
- applyCreate(plan: Plan<TestConfig>): Promise<void> {
11
- return Promise.resolve(undefined);
12
- }
8
+ export interface TestConfig extends StringIndexedObject {
9
+ propA: string;
10
+ propB: number;
11
+ propC?: string;
12
+ }
13
13
 
14
- applyDestroy(plan: Plan<TestConfig>): Promise<void> {
15
- return Promise.resolve(undefined);
14
+ export class TestResource extends Resource<TestConfig> {
15
+ constructor(options: ResourceConfiguration<TestConfig>) {
16
+ super(options);
16
17
  }
17
18
 
18
- applyModify(plan: Plan<TestConfig>): Promise<void> {
19
+ applyCreate(plan: Plan<TestConfig>): Promise<void> {
19
20
  return Promise.resolve(undefined);
20
21
  }
21
22
 
22
- applyRecreate(plan: Plan<TestConfig>): Promise<void> {
23
+ applyDestroy(plan: Plan<TestConfig>): Promise<void> {
23
24
  return Promise.resolve(undefined);
24
25
  }
25
26
 
26
- calculateOperation(change: ParameterChange): ResourceOperation.RECREATE | ResourceOperation.MODIFY {
27
- return ResourceOperation.MODIFY;
28
- }
29
-
30
- async getCurrentConfig(): Promise<TestConfig | null> {
31
- return null;
32
- }
33
-
34
- async validate(config: ResourceConfig): Promise<string | undefined> {
35
- return undefined;
27
+ async refresh(): Promise<Partial<TestConfig> | null> {
28
+ return {
29
+ propA: 'a',
30
+ propB: 10,
31
+ propC: 'c',
32
+ };
36
33
  }
37
34
 
38
- getTypeId(): string {
39
- return '';
35
+ async validate(config: unknown): Promise<ValidationResult> {
36
+ return {
37
+ isValid: true
38
+ }
40
39
  }
41
40
  }
42
41
 
43
- interface TestConfig extends ResourceConfig {
44
- propA: string;
45
- propB: number;
46
- propC?: string;
47
- }
48
-
49
42
  describe('Resource tests', () => {
50
43
  it('plans correctly', async () => {
51
44
  const resource = new class extends TestResource {
52
- calculateOperation(change: ParameterChange): ResourceOperation.RECREATE | ResourceOperation.MODIFY {
53
- return ResourceOperation.MODIFY;
45
+ constructor() {
46
+ super({ type: 'type' });
54
47
  }
55
48
 
56
- async getCurrentConfig(): Promise<TestConfig> {
49
+ async refresh(): Promise<TestConfig> {
57
50
  return {
58
- type: 'type',
59
- name: 'name',
60
- propA: "propABefore",
51
+ propA: 'propABefore',
61
52
  propB: 10,
62
53
  };
63
54
  }
@@ -71,20 +62,20 @@ describe('Resource tests', () => {
71
62
  propB: 10,
72
63
  })
73
64
 
74
- expect(result.resourceConfig).to.deep.eq({
65
+ expect(result.desiredConfig).to.deep.eq({
75
66
  type: 'type',
76
67
  name: 'name',
77
68
  propA: 'propA',
78
69
  propB: 10,
79
70
  });
80
- expect(result.changeSet.operation).to.eq(ResourceOperation.MODIFY);
71
+ expect(result.changeSet.operation).to.eq(ResourceOperation.RECREATE);
81
72
  expect(result.changeSet.parameterChanges[0]).to.deep.eq({
82
73
  name: 'propA',
83
74
  previousValue: 'propABefore',
84
75
  newValue: 'propA',
85
76
  operation: 'modify'
86
77
  })
87
- expect(result.changeSet.parameterChanges[1]).to.deep.eq( {
78
+ expect(result.changeSet.parameterChanges[1]).to.deep.eq({
88
79
  name: 'propB',
89
80
  previousValue: 10,
90
81
  newValue: 10,
@@ -92,25 +83,19 @@ describe('Resource tests', () => {
92
83
  })
93
84
  })
94
85
 
95
- it('calls calculateOperation for only modifications and recreates', async () => {
86
+ it('creates the resource if it doesnt exist', async () => {
96
87
  const resource = new class extends TestResource {
97
- calculateOperation(change: ParameterChange): ResourceOperation.RECREATE | ResourceOperation.MODIFY {
98
- return ResourceOperation.MODIFY;
88
+ constructor() {
89
+ super({ type: 'type' });
99
90
  }
100
91
 
101
- async getCurrentConfig(): Promise<TestConfig> {
102
- return {
103
- type: 'type',
104
- name: 'name',
105
- propA: "propABefore",
106
- propB: 10,
107
- propC: 'somethingBefore'
108
- };
92
+ async refresh(): Promise<TestConfig | null> {
93
+ return null;
109
94
  }
110
95
  }
111
96
 
112
97
  const resourceSpy = spy(resource);
113
- await resourceSpy.plan({
98
+ const result = await resourceSpy.plan({
114
99
  type: 'type',
115
100
  name: 'name',
116
101
  propA: 'propA',
@@ -118,45 +103,41 @@ describe('Resource tests', () => {
118
103
  propC: 'somethingAfter'
119
104
  })
120
105
 
121
- expect(resourceSpy.calculateOperation.calledTwice).to.be.true;
106
+ expect(result.changeSet.operation).to.eq(ResourceOperation.CREATE);
107
+ expect(result.changeSet.parameterChanges.length).to.eq(3);
122
108
  })
123
109
 
124
- it('creates the resource if it doesnt exist', async () => {
110
+ it('handles empty parameters', async () => {
125
111
  const resource = new class extends TestResource {
126
- calculateOperation(change: ParameterChange): ResourceOperation.RECREATE | ResourceOperation.MODIFY {
127
- return ResourceOperation.MODIFY;
112
+ constructor() {
113
+ super({ type: 'type' });
128
114
  }
129
115
 
130
- async getCurrentConfig(): Promise<TestConfig | null> {
116
+ async refresh(): Promise<Partial<TestConfig> | null> {
131
117
  return null;
132
118
  }
133
119
  }
134
120
 
135
121
  const resourceSpy = spy(resource);
136
- const result = await resourceSpy.plan({
137
- type: 'type',
138
- name: 'name',
139
- propA: 'propA',
140
- propB: 10,
141
- propC: 'somethingAfter'
142
- })
122
+ const result = await resourceSpy.plan({ type: 'type' })
143
123
 
144
124
  expect(result.changeSet.operation).to.eq(ResourceOperation.CREATE);
145
- expect(result.changeSet.parameterChanges.length).to.eq(3);
125
+ expect(result.changeSet.parameterChanges.length).to.eq(0);
146
126
  })
147
127
 
148
128
  it('chooses the create apply properly', async () => {
149
129
  const resource = new class extends TestResource {
150
- getTypeId(): string {
151
- return 'resource'
130
+ constructor() {
131
+ super({ type: 'resource' });
152
132
  }
153
133
  }
154
134
 
155
135
  const resourceSpy = spy(resource);
156
136
  const result = await resourceSpy.apply(
157
- Plan.create(
158
- new ChangeSet(ResourceOperation.CREATE, []),
159
- { type: 'resource', propA: 'a', propB: 0 }
137
+ Plan.create<TestConfig>(
138
+ { type: 'resource', propA: 'a', propB: 0 },
139
+ { type: 'resource' },
140
+ { statefulMode: false },
160
141
  )
161
142
  )
162
143
 
@@ -165,186 +146,67 @@ describe('Resource tests', () => {
165
146
 
166
147
  it('chooses the destroy apply properly', async () => {
167
148
  const resource = new class extends TestResource {
168
- getTypeId(): string {
169
- return 'resource'
149
+ constructor() {
150
+ super({ type: 'resource' });
170
151
  }
171
152
  }
172
153
 
173
154
  const resourceSpy = spy(resource);
174
155
  const result = await resourceSpy.apply(
175
- Plan.create(
176
- new ChangeSet(ResourceOperation.DESTROY, []),
177
- { type: 'resource', propA: 'a', propB: 0 }
156
+ Plan.create<TestConfig>(
157
+ { type: 'resource' },
158
+ { type: 'resource', propA: 'a', propB: 0 },
159
+ { statefulMode: true },
178
160
  )
179
161
  )
180
162
 
181
163
  expect(resourceSpy.applyDestroy.calledOnce).to.be.true;
182
164
  })
183
165
 
184
- it('calls apply modify', async () => {
166
+ it('Defaults parameter changes to recreate', async () => {
185
167
  const resource = new class extends TestResource {
186
- getTypeId(): string {
187
- return 'resource'
188
- }
189
- }
190
-
191
- const resourceSpy = spy(resource);
192
- const result = await resourceSpy.apply(
193
- Plan.create(
194
- new ChangeSet(ResourceOperation.MODIFY, [
195
- {
196
- name: 'propA',
197
- newValue: 'a',
198
- previousValue: 'b',
199
- operation: ParameterOperation.ADD,
200
- },
201
- {
202
- name: 'propB',
203
- newValue: 0,
204
- previousValue: -1,
205
- operation: ParameterOperation.ADD,
206
- },
207
- ]),
208
- { type: 'resource', propA: 'a', propB: 0 }
209
- )
210
- );
211
-
212
- expect(resourceSpy.applyModify.calledOnce).to.be.true;
213
- })
214
-
215
- it('supports the creation of stateful parameters', async () => {
216
- const statefulParameter = new class implements StatefulParameter<TestConfig, 'propA'> {
217
- get name(): "propA" {
218
- return 'propA';
219
- }
220
-
221
- applyAdd(parameterChange: ParameterChange, plan: Plan<TestConfig>): Promise<void> {
222
- return Promise.resolve(undefined);
223
- }
224
-
225
- applyModify(parameterChange: ParameterChange, plan: Plan<TestConfig>): Promise<void> {
226
- return Promise.resolve(undefined);
227
- }
228
-
229
- applyRemove(parameterChange: ParameterChange, plan: Plan<TestConfig>): Promise<void> {
230
- return Promise.resolve(undefined);
231
- }
232
-
233
- async getCurrent(): Promise<TestConfig["propA"]> {
234
- return '';
235
- }
236
- }
237
-
238
- const statefulParameterSpy = spy(statefulParameter);
239
-
240
- const resource = new class extends TestResource {
241
-
242
168
  constructor() {
243
- super();
244
- this.registerStatefulParameter(statefulParameterSpy)
245
- }
246
-
247
- getTypeId(): string {
248
- return 'resource'
169
+ super({ type: 'resource' });
249
170
  }
250
171
  }
251
172
 
252
173
  const resourceSpy = spy(resource);
253
174
  const result = await resourceSpy.apply(
254
- Plan.create(
255
- new ChangeSet(ResourceOperation.CREATE, [
256
- {
257
- name: 'propA',
258
- newValue: 'a',
259
- previousValue: null,
260
- operation: ParameterOperation.ADD,
261
- },
262
- {
263
- name: 'propB',
264
- newValue: 0,
265
- previousValue: null,
266
- operation: ParameterOperation.ADD,
267
- },
268
- {
269
- name: 'propC',
270
- newValue: 'b',
271
- previousValue: null,
272
- operation: ParameterOperation.ADD,
273
- },
274
- ]),
275
- { type: 'resource', propA: 'a', propB: 0, propC: 'b' }
175
+ Plan.create<TestConfig>(
176
+ { type: 'resource', propA: 'a', propB: 0 },
177
+ { type: 'resource', propA: 'b', propB: -1 },
178
+ { statefulMode: true },
276
179
  )
277
180
  );
278
181
 
279
- expect(statefulParameterSpy.applyAdd.calledOnce).to.be.true;
182
+ expect(resourceSpy.applyDestroy.calledOnce).to.be.true;
280
183
  expect(resourceSpy.applyCreate.calledOnce).to.be.true;
281
184
  })
282
185
 
283
- it('supports the modification of stateful parameters', async () => {
284
- const statefulParameter = new class implements StatefulParameter<TestConfig, 'propA'> {
285
- get name(): "propA" {
286
- return 'propA';
287
- }
288
-
289
- applyAdd(parameterChange: ParameterChange, plan: Plan<TestConfig>): Promise<void> {
290
- return Promise.resolve(undefined);
291
- }
292
-
293
- applyModify(parameterChange: ParameterChange, plan: Plan<TestConfig>): Promise<void> {
294
- return Promise.resolve(undefined);
295
- }
296
-
297
- applyRemove(parameterChange: ParameterChange, plan: Plan<TestConfig>): Promise<void> {
298
- return Promise.resolve(undefined);
299
- }
300
-
301
- async getCurrent(): Promise<TestConfig["propA"]> {
302
- return '';
303
- }
304
- }
305
-
306
- const statefulParameterSpy = spy(statefulParameter);
307
-
186
+ it('Allows modification of parameter behavior to allow modify for parameters', async () => {
308
187
  const resource = new class extends TestResource {
309
-
310
188
  constructor() {
311
- super();
312
- this.registerStatefulParameter(statefulParameterSpy)
189
+ super({
190
+ type: 'resource',
191
+ parameterConfigurations: {
192
+ propA: { planOperation: ResourceOperation.MODIFY },
193
+ propB: { planOperation: ResourceOperation.MODIFY },
194
+ }
195
+ });
313
196
  }
314
197
 
315
- getTypeId(): string {
316
- return 'resource'
198
+ async refresh(): Promise<TestConfig | null> {
199
+ return { propA: 'b', propB: -1 };
317
200
  }
318
201
  }
319
202
 
203
+ const plan = await resource.plan({ type: 'resource', propA: 'a', propB: 0 })
204
+
320
205
  const resourceSpy = spy(resource);
321
206
  const result = await resourceSpy.apply(
322
- Plan.create(
323
- new ChangeSet(ResourceOperation.MODIFY, [
324
- {
325
- name: 'propA',
326
- newValue: 'a',
327
- previousValue: 'b',
328
- operation: ParameterOperation.MODIFY,
329
- },
330
- {
331
- name: 'propB',
332
- newValue: 0,
333
- previousValue: null,
334
- operation: ParameterOperation.ADD,
335
- },
336
- {
337
- name: 'propC',
338
- newValue: 'b',
339
- previousValue: 'b',
340
- operation: ParameterOperation.NOOP,
341
- },
342
- ]),
343
- { type: 'resource', propA: 'a', propB: 0, propC: 'b' }
344
- )
207
+ plan
345
208
  );
346
209
 
347
- expect(statefulParameterSpy.applyModify.calledOnce).to.be.true;
348
- expect(resourceSpy.applyModify.calledOnce).to.be.true;
210
+ expect(resourceSpy.applyModify.calledTwice).to.be.true;
349
211
  })
350
- })
212
+ });