Skip to content

Commit 64f065a

Browse files
authored
Make KptFunc async (#81)
1 parent 6a87fe7 commit 64f065a

35 files changed

+326
-281
lines changed

docs/api/classes/_testing_.testrunner.md

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Class: TestRunner
44

5-
TestRunner makes it easier to write table-driven tests for KPT functions.
5+
TestRunner makes it easy to write unit tests for KPT functions.
66

77
## Hierarchy
88

@@ -16,7 +16,8 @@ TestRunner makes it easier to write table-driven tests for KPT functions.
1616

1717
### Methods
1818

19-
* [run](_testing_.testrunner.md#run)
19+
* [assert](_testing_.testrunner.md#assert)
20+
* [assertCallback](_testing_.testrunner.md#assertcallback)
2021

2122
## Constructors
2223

@@ -34,20 +35,58 @@ Name | Type |
3435

3536
## Methods
3637

37-
### run
38+
### assert
3839

39-
**run**(`input`: [Configs](_types_.configs.md), `expectedOutput?`: [Configs](_types_.configs.md) | [ConfigError](_errors_.configerror.md), `expectException?`: undefined | false | true): *function*
40+
**assert**(`input`: [Configs](_types_.configs.md), `expectedOutput?`: [Configs](_types_.configs.md), `expectedException?`: undefined | object, `expectedExceptionMessage?`: string | RegExp): *Promise‹void›*
4041

41-
Generates a callback for a test framework to execute.
42+
Runs the KptFunc and asserts the expected output or exception.
43+
44+
Example usage:
45+
46+
```
47+
const RUNNER = new TestRunner(myFunc);
48+
49+
it('function is a NO OP', async () => {
50+
await RUNNER.assert());
51+
};
52+
```
53+
54+
**Parameters:**
55+
56+
Name | Type | Default | Description |
57+
------ | ------ | ------ | ------ |
58+
`input` | [Configs](_types_.configs.md) | new Configs() | input Configs passed to the function. It is deep-copied before running the function. If undefined, assumes an empty Configs. |
59+
`expectedOutput?` | [Configs](_types_.configs.md) | - | expected resultant Configs after KptFunc has successfully completed. If undefined, assumes the output should remain unchanged (NO OP). |
60+
`expectedException?` | undefined | object | - | expected exception to be thrown. If given, expectedOutput is ignored. |
61+
`expectedExceptionMessage?` | string | RegExp | - | expected message of expection to be thrown. If given, expectedOutput is ignored. |
62+
63+
**Returns:** *Promise‹void›*
64+
65+
___
66+
67+
### assertCallback
68+
69+
**assertCallback**(`input`: [Configs](_types_.configs.md), `expectedOutput?`: [Configs](_types_.configs.md), `expectedException?`: undefined | object, `expectedExceptionMessage?`: string | RegExp): *function*
70+
71+
Similar to [assert](_testing_.testrunner.md#assert) method, but instead returns an assertion function that can be passed directly to 'it'.
72+
73+
Example usage:
74+
75+
```
76+
const RUNNER = new TestRunner(myFunc);
77+
78+
it('function is a NO OP', RUNNER.assertCallback());
79+
```
4280

4381
**Parameters:**
4482

4583
Name | Type | Default | Description |
4684
------ | ------ | ------ | ------ |
47-
`input` | [Configs](_types_.configs.md) | new Configs() | is the initial set of Configs to test. By default assumes an empty set of Configs. |
48-
`expectedOutput?` | [Configs](_types_.configs.md) | [ConfigError](_errors_.configerror.md) | - | is the expected resulting Configs or ConfigError produced by the KptFunc. If undefined, assumes the output should remain unchanged. |
49-
`expectException?` | undefined | false | true | - | indicates that KptFunc is expected to throw an exception. |
85+
`input` | [Configs](_types_.configs.md) | new Configs() | input Configs passed to the function. It is deep-copied before running the function. If undefined, assumes an empty Configs. |
86+
`expectedOutput?` | [Configs](_types_.configs.md) | - | expected resultant Configs after KptFunc has successfully completed. If undefined, assumes the output should remain unchanged (NO OP). |
87+
`expectedException?` | undefined | object | - | expected exception to be thrown. If given, expectedOutput is ignored. |
88+
`expectedExceptionMessage?` | string | RegExp | - | expected message of expection to be thrown. If given, expectedOutput is ignored. |
5089

5190
**Returns:** *function*
5291

53-
▸ (): *void*
92+
▸ (): *Promise‹void*

docs/api/classes/_types_.configs.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ ___
139139

140140
Returns the value for the given key if functionConfig is of kind ConfigMap.
141141

142-
Throws an exception if functionConfig kind is not a ConfigMap.
142+
Throws a TypeError exception if functionConfig kind is not a ConfigMap.
143143

144144
Returns undefined if functionConfig is undefined OR
145145
if the ConfigMap has no such key in the 'data' section.
@@ -160,7 +160,7 @@ ___
160160

161161
**getFunctionConfigValueOrThrow**(`key`: string): *string*
162162

163-
Similar to [getFunctionConfigValue](_types_.configs.md#getfunctionconfigvalue) except it throws an exception if the given key is undefined.
163+
Similar to [getFunctionConfigValue](_types_.configs.md#getfunctionconfigvalue) except it throws a TypeError exception if the given key is undefined.
164164

165165
**Parameters:**
166166

@@ -182,7 +182,9 @@ The ordering of objects with the same key is deterministic.
182182

183183
Example: Partition configs by Namespace:
184184

185+
```
185186
const configsByNamespace = configs.groupBy((o) => o.metadata.namespace)
187+
```
186188

187189
**Parameters:**
188190

docs/api/interfaces/_types_.kptfunc.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ Interface describing KPT functions.
1010

1111
## Callable
1212

13-
▸ (`configs`: [Configs](../classes/_types_.configs.md)): *void | [ConfigError](../classes/_errors_.configerror.md)*
13+
▸ (`configs`: [Configs](../classes/_types_.configs.md)): *Promise‹void*
1414

1515
A function consumes and optionally mutates Kubernetes configurations using the given [Configs](../classes/_types_.configs.md) object.
1616

1717
The function should:
18-
- Return a [ConfigError](../classes/_errors_.configerror.md) when encountering one or more configuration-related issues.
19-
- Throw an error when encountering operational issues such as IO exceptions.
18+
- Throw a [ConfigError](../classes/_errors_.configerror.md) when encountering one or more configuration-related issues.
19+
- Throw other error types when encountering operational issues such as IO exceptions.
2020
- Avoid writing to stdout (e.g. using process.stdout) as it is used for chaining functions.
2121
Use stderr instead.
2222

@@ -26,7 +26,7 @@ Name | Type |
2626
------ | ------ |
2727
`configs` | [Configs](../classes/_types_.configs.md) |
2828

29-
**Returns:** *void | [ConfigError](../classes/_errors_.configerror.md)*
29+
**Returns:** *Promise‹void*
3030

3131
## Index
3232

docs/api/modules/_run_.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@
1212

1313
### run
1414

15-
**run**(`fn`: [KptFunc](../interfaces/_types_.kptfunc.md)): *void*
15+
**run**(`fn`: [KptFunc](../interfaces/_types_.kptfunc.md)): *Promise‹void*
1616

17-
Executes the KptFunc. This is the main entrypoint for all kpt functions.
17+
This is the main entrypoint for running a KPT function.
18+
19+
This method does not throw any errors and can be invoked at the top-level without getting
20+
an unhandled promise rejection error.
1821

1922
**Parameters:**
2023

2124
Name | Type |
2225
------ | ------ |
2326
`fn` | [KptFunc](../interfaces/_types_.kptfunc.md) |
2427

25-
**Returns:** *void*
28+
**Returns:** *Promise‹void*

tests/e2e.bats

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,35 @@ function runp() {
2222

2323
@test "no-op print stdout" {
2424
runp "docker run -i gcr.io/kpt-functions/no-op:${TAG} -i /dev/null"
25+
[ "$status" -eq 0 ]
2526
[ "$output" = "${EMPTY_OUTPUT}" ]
2627
}
2728

2829
@test "no-op pipe" {
2930
runp "docker run -i gcr.io/kpt-functions/no-op:${TAG} -i /dev/null |
3031
docker run -i gcr.io/kpt-functions/no-op:${TAG}"
32+
[ "$status" -eq 0 ]
3133
[ "$output" = "${EMPTY_OUTPUT}" ]
3234
}
3335

3436
@test "no-op output to /dev/null" {
35-
runp "docker run -i gcr.io/kpt-functions/no-op:${TAG} -i /dev/null |
36-
docker run -i gcr.io/kpt-functions/no-op:${TAG} |
37-
docker run -i gcr.io/kpt-functions/no-op:${TAG} -o /dev/null"
38-
[ "$output" = "" ]
37+
runp "docker run -i gcr.io/kpt-functions/no-op:${TAG} -i /dev/null |
38+
docker run -i gcr.io/kpt-functions/no-op:${TAG} |
39+
docker run -i gcr.io/kpt-functions/no-op:${TAG} -o /dev/null"
40+
[ "$status" -eq 0 ]
41+
[ "$output" = "" ]
42+
}
43+
44+
@test "all demo functions" {
45+
runp "docker run -i -u $(id -u) -v $(pwd):/source gcr.io/kpt-functions/read-yaml:${TAG} -i /dev/null -d source_dir=/source |
46+
docker run -i gcr.io/kpt-functions/mutate-psp:${TAG} |
47+
docker run -i gcr.io/kpt-functions/expand-team-cr:${TAG} |
48+
docker run -i gcr.io/kpt-functions/validate-rolebinding:${TAG} -d [email protected] |
49+
docker run -i -u $(id -u) -v $(pwd):/sink gcr.io/kpt-functions/write-yaml:${TAG} -o /dev/null -d sink_dir=/sink -d overwrite=true"
50+
[ "$status" -eq 0 ]
51+
[ "$output" = "" ]
52+
53+
# Check expected diff
54+
ls payments-dev payments-prod
55+
grep allowPrivilegeEscalation podsecuritypolicy_psp.yaml
3956
}

ts/create-kpt-functions/templates/func.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { KptFunc } from '@googlecontainertools/kpt-functions';
1+
import { Configs } from '@googlecontainertools/kpt-functions';
22

3-
export const {{func_name}}: KptFunc = (configs) => {
3+
export async function {{func_name}}(configs: Configs) {
44
// TODO: implement.
55
};
66

ts/create-kpt-functions/templates/package.json.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"kpt:type-create": "kpt type-create"
1616
},
1717
"dependencies": {
18-
"@googlecontainertools/kpt-functions": "^0.10.0"
18+
"@googlecontainertools/kpt-functions": "^0.11.0-rc.1"
1919
},
2020
"devDependencies": {
2121
"@googlecontainertools/create-kpt-functions": "^0.14.4",
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
import { Configs } from '@googlecontainertools/kpt-functions';
1+
import { Configs, TestRunner } from '@googlecontainertools/kpt-functions';
22
import { {{{func_name}}} } from './{{{file_name}}}';
33

4-
describe('{{{func_name}}}', () => {
5-
it('does something', () => {
6-
// 1. TODO: Create test fixture for Configs consumed by the function.
7-
const actualConfigs = new Configs();
4+
const RUNNER = new TestRunner({{{func_name}}});
85

9-
// 2. Invoke the function.
10-
{{{func_name}}}(actualConfigs);
6+
describe('{{{func_name}}}', () => {
7+
it('does something', async () => {
8+
// TODO: Populate the input to the function.
9+
const input = new Configs();
1110
12-
// 3. TODO: Create test fixture for Configs expected to be returned by the function.
13-
const expectedConfigs = new Configs();
11+
// TODO: Populate the expected output of the function.
12+
const expectedOutput = new Configs();
1413
15-
// 4. TODO: Assert function behavior including any side-effects.
16-
expect(actualConfigs.getAll()).toEqual(expectedConfigs.getAll());
14+
await RUNNER.assert(input, expectedOutput);
1715
});
1816
});

ts/demo-functions/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ts/demo-functions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"kpt:type-create": "kpt type-create"
2323
},
2424
"dependencies": {
25-
"@googlecontainertools/kpt-functions": "^0.10.0",
25+
"@googlecontainertools/kpt-functions": "^0.11.0-rc.1",
2626
"glob": "^7.1.3",
2727
"js-yaml": "^3.13.1"
2828
},

0 commit comments

Comments
 (0)