Skip to content

Commit

Permalink
feat(sdk): only generate test-running resources on clouds when runnin…
Browse files Browse the repository at this point in the history
…g `wing test` (#4098)

It was brought up in a recent discussion about testing that it's unusual how `test` statements create resources in cloud provider accounts even when you have only compiled your application to run in production. This PR changes the behavior so that test resources are only generated when running `wing test`, or when using the simulator target (since there's no cost of simulated resources). 

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [ ] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
Chriscbr authored Sep 7, 2023
1 parent 703ee66 commit eaba03a
Show file tree
Hide file tree
Showing 158 changed files with 209 additions and 19,014 deletions.
11 changes: 11 additions & 0 deletions libs/wingsdk/src/core/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ export abstract class App extends Construct {
}
}

/**
* The name of the compilation target.
* @internal
*/
public abstract readonly _target:
| "sim"
| "tf-aws"
| "tf-azure"
| "tf-gcp"
| "awscdk";

/**
* Wing source files directory absolute path
*/
Expand Down
24 changes: 15 additions & 9 deletions libs/wingsdk/src/std/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ export class Test extends Resource implements IInflightHost {
return App.of(scope).newAbstract(TEST_FQN, scope, id, inflight, props);
}

/** @internal */
public readonly _fn: Function;
/**
* The function that will be called when the test is run. This will only be created
* if the app is compiled with `wing test` for a non-simulator target.
* @internal
*/
public readonly _fn: Function | undefined;

constructor(
scope: Construct,
Expand All @@ -52,13 +56,15 @@ export class Test extends Resource implements IInflightHost {
Node.of(this).title = "Test";
Node.of(this).description = "A cloud unit test.";

this._fn = App.of(scope).newAbstract(
FUNCTION_FQN,
this,
"Handler",
inflight,
props
);
if (App.of(this).isTestEnvironment || App.of(this)._target === "sim") {
this._fn = App.of(scope).newAbstract(
FUNCTION_FQN,
this,
"Handler",
inflight,
props
);
}
}

/** @internal */
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-awscdk/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export class App extends CoreApp {
public readonly isTestEnvironment: boolean;
public readonly _tokens: CdkTokens;

public readonly _target = "awscdk";

private readonly cdkApp: cdk.App;
private readonly cdkStack: cdk.Stack;
private readonly pluginManager: PluginManager;
Expand Down
16 changes: 10 additions & 6 deletions libs/wingsdk/src/target-awscdk/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export class TestRunner extends std.TestRunner {
public _preSynthesize(): void {
// add a dependency on each test function
for (const test of this.findTests()) {
this.node.addDependency(test._fn);
if (test._fn) {
this.node.addDependency(test._fn);
}
}

super._preSynthesize();
Expand All @@ -65,12 +67,14 @@ export class TestRunner extends std.TestRunner {
private getTestFunctionArns(): Map<string, string> {
const arns = new Map<string, string>();
for (const test of this.findTests()) {
if (!(test._fn instanceof AwsFunction)) {
throw new Error(
`Unsupported test function type, ${test._fn.node.path} was not a tfaws.Function`
);
if (test._fn) {
if (!(test._fn instanceof AwsFunction)) {
throw new Error(
`Unsupported test function type, ${test._fn.node.path} was not a tfaws.Function`
);
}
arns.set(test.node.path, (test._fn as AwsFunction).arn);
}
arns.set(test.node.path, (test._fn as AwsFunction).arn);
}
return arns;
}
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-sim/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class App extends core.App {
public readonly isTestEnvironment: boolean;
public readonly _tokens: SimTokens;

public readonly _target = "sim";

/**
* The test runner for this app.
*/
Expand Down
8 changes: 6 additions & 2 deletions libs/wingsdk/src/target-sim/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export class TestRunner extends std.TestRunner implements ISimulatorResource {
public _preSynthesize(): void {
// add a dependency on each test function
for (const test of this.findTests()) {
this.node.addDependency(test._fn);
if (test._fn) {
this.node.addDependency(test._fn);
}
}

super._preSynthesize();
Expand All @@ -48,7 +50,9 @@ export class TestRunner extends std.TestRunner implements ISimulatorResource {
private getTestFunctionHandles(): Record<string, string> {
const handles: Record<string, string> = {};
for (const test of this.findTests()) {
handles[test.node.path] = simulatorHandleToken(test._fn);
if (test._fn) {
handles[test.node.path] = simulatorHandleToken(test._fn);
}
}
return handles;
}
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-aws/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class App extends CdktfApp {
*/
protected readonly testRunner: TestRunner;

public readonly _target = "tf-aws";

private awsRegionProvider?: DataAwsRegion;
private awsAccountIdProvider?: DataAwsCallerIdentity;
private _vpc?: Vpc;
Expand Down
16 changes: 10 additions & 6 deletions libs/wingsdk/src/target-tf-aws/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export class TestRunner extends std.TestRunner {
public _preSynthesize(): void {
// add a dependency on each test function
for (const test of this.findTests()) {
this.node.addDependency(test._fn);
if (test._fn) {
this.node.addDependency(test._fn);
}
}

super._preSynthesize();
Expand All @@ -65,12 +67,14 @@ export class TestRunner extends std.TestRunner {
private getTestFunctionArns(): Map<string, string> {
const arns = new Map<string, string>();
for (const test of this.findTests()) {
if (!(test._fn instanceof AwsFunction)) {
throw new Error(
`Unsupported test function type, ${test._fn.node.path} was not a tfaws.Function`
);
if (test._fn) {
if (!(test._fn instanceof AwsFunction)) {
throw new Error(
`Unsupported test function type, ${test._fn.node.path} was not a tfaws.Function`
);
}
arns.set(test.node.path, (test._fn as AwsFunction).arn);
}
arns.set(test.node.path, (test._fn as AwsFunction).arn);
}
return arns;
}
Expand Down
1 change: 1 addition & 0 deletions libs/wingsdk/src/target-tf-azure/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class App extends CdktfApp {
* @link https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group#location
* */
public readonly location: string;
public readonly _target = "tf-azure";
private _resourceGroup?: ResourceGroup;
private _storageAccount?: StorageAccount;
private _servicePlan?: ServicePlan;
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-gcp/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export class App extends CdktfApp {
*/
public readonly storageLocation: string;

public readonly _target = "tf-gcp";

constructor(props: AppProps) {
super(props);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module.exports = function({ $api_url, $http_Util }) {
},
"output": {
"WING_TEST_RUNNER_FUNCTION_ARNS": {
"value": "[[\"root/Default/Default/test:it responds with 404\",\"${aws_lambda_function.testitrespondswith404_Handler_2D34428F.arn}\"]]"
"value": "[]"
}
},
"provider": {
Expand Down Expand Up @@ -132,15 +132,6 @@ module.exports = function({ $api_url, $http_Util }) {
}
},
"assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Effect\":\"Allow\"}]}"
},
"testitrespondswith404_Handler_IamRole_E0973EE8": {
"//": {
"metadata": {
"path": "root/Default/Default/test:it responds with 404/Handler/IamRole",
"uniqueId": "testitrespondswith404_Handler_IamRole_E0973EE8"
}
},
"assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Effect\":\"Allow\"}]}"
}
},
"aws_iam_role_policy": {
Expand All @@ -153,16 +144,6 @@ module.exports = function({ $api_url, $http_Util }) {
},
"policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"none:null\",\"Resource\":\"*\"}]}",
"role": "${aws_iam_role.cloudApi_cloudApi-OnRequest-cdafee6e_IamRole_4382C442.name}"
},
"testitrespondswith404_Handler_IamRolePolicy_4E2D3D6D": {
"//": {
"metadata": {
"path": "root/Default/Default/test:it responds with 404/Handler/IamRolePolicy",
"uniqueId": "testitrespondswith404_Handler_IamRolePolicy_4E2D3D6D"
}
},
"policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"none:null\",\"Resource\":\"*\"}]}",
"role": "${aws_iam_role.testitrespondswith404_Handler_IamRole_E0973EE8.name}"
}
},
"aws_iam_role_policy_attachment": {
Expand All @@ -175,16 +156,6 @@ module.exports = function({ $api_url, $http_Util }) {
},
"policy_arn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"role": "${aws_iam_role.cloudApi_cloudApi-OnRequest-cdafee6e_IamRole_4382C442.name}"
},
"testitrespondswith404_Handler_IamRolePolicyAttachment_943423A4": {
"//": {
"metadata": {
"path": "root/Default/Default/test:it responds with 404/Handler/IamRolePolicyAttachment",
"uniqueId": "testitrespondswith404_Handler_IamRolePolicyAttachment_943423A4"
}
},
"policy_arn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"role": "${aws_iam_role.testitrespondswith404_Handler_IamRole_E0973EE8.name}"
}
},
"aws_lambda_function": {
Expand Down Expand Up @@ -216,36 +187,6 @@ module.exports = function({ $api_url, $http_Util }) {
"security_group_ids": [],
"subnet_ids": []
}
},
"testitrespondswith404_Handler_2D34428F": {
"//": {
"metadata": {
"path": "root/Default/Default/test:it responds with 404/Handler/Default",
"uniqueId": "testitrespondswith404_Handler_2D34428F"
}
},
"architectures": [
"arm64"
],
"environment": {
"variables": {
"WING_FUNCTION_NAME": "Handler-c83f9661",
"WING_TARGET": "tf-aws",
"WING_TOKEN_TFTOKEN_TOKEN_8": "${jsonencode(aws_api_gateway_stage.cloudApi_api_stage_BBB283E4.invoke_url)}"
}
},
"function_name": "Handler-c83f9661",
"handler": "index.handler",
"publish": true,
"role": "${aws_iam_role.testitrespondswith404_Handler_IamRole_E0973EE8.arn}",
"runtime": "nodejs18.x",
"s3_bucket": "${aws_s3_bucket.Code.bucket}",
"s3_key": "${aws_s3_object.testitrespondswith404_Handler_S3Object_7180AA4B.key}",
"timeout": 30,
"vpc_config": {
"security_group_ids": [],
"subnet_ids": []
}
}
},
"aws_lambda_permission": {
Expand Down Expand Up @@ -285,17 +226,6 @@ module.exports = function({ $api_url, $http_Util }) {
"bucket": "${aws_s3_bucket.Code.bucket}",
"key": "<ASSET_KEY>",
"source": "<ASSET_SOURCE>"
},
"testitrespondswith404_Handler_S3Object_7180AA4B": {
"//": {
"metadata": {
"path": "root/Default/Default/test:it responds with 404/Handler/S3Object",
"uniqueId": "testitrespondswith404_Handler_S3Object_7180AA4B"
}
},
"bucket": "${aws_s3_bucket.Code.bucket}",
"key": "<ASSET_KEY>",
"source": "<ASSET_SOURCE>"
}
}
}
Expand Down
Loading

0 comments on commit eaba03a

Please sign in to comment.