Skip to content

Commit 33c2504

Browse files
authored
Converge CloudFormationFunctionNode and LambdaFunctionNode (#802)
1 parent 18da85b commit 33c2504

File tree

8 files changed

+137
-106
lines changed

8 files changed

+137
-106
lines changed

src/awsexplorer/awsExplorer.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import { deleteCloudFormation } from '../lambda/commands/deleteCloudFormation'
88
import { deleteLambda } from '../lambda/commands/deleteLambda'
99
import { invokeLambda } from '../lambda/commands/invokeLambda'
1010
import { CloudFormationStackNode } from '../lambda/explorer/cloudFormationNodes'
11-
import { FunctionNodeBase } from '../lambda/explorer/functionNode'
12-
import { LambdaFunctionNode } from '../lambda/explorer/lambdaNodes'
11+
import { LambdaFunctionNode } from '../lambda/explorer/lambdaFunctionNode'
1312
import { configureLocalLambda } from '../lambda/local/configureLocalLambda'
1413
import { AwsContext } from '../shared/awsContext'
1514
import { AwsContextTreeCollection } from '../shared/awsContextTreeCollection'
@@ -83,7 +82,7 @@ export class AwsExplorer implements vscode.TreeDataProvider<AWSTreeNodeBase>, Re
8382

8483
registerCommand({
8584
command: 'aws.invokeLambda',
86-
callback: async (node: FunctionNodeBase) =>
85+
callback: async (node: LambdaFunctionNode) =>
8786
await invokeLambda({
8887
awsContext: this.awsContext,
8988
functionNode: node,

src/lambda/commands/invokeLambda.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { ResourceFetcher } from '../../shared/resourceFetcher'
1717
import { FileResourceLocation, WebResourceLocation } from '../../shared/resourceLocation'
1818
import { BaseTemplates } from '../../shared/templates/baseTemplates'
1919
import { sampleRequestManifestPath, sampleRequestPath } from '../constants'
20-
import { FunctionNodeBase } from '../explorer/functionNode'
20+
import { LambdaFunctionNode } from '../explorer/lambdaFunctionNode'
2121
import { SampleRequest } from '../models/sampleRequest'
2222
import { LambdaTemplates } from '../templates/lambdaTemplates'
2323

@@ -45,7 +45,7 @@ export async function invokeLambda(params: {
4545
awsContext: AwsContext // TODO: Consider replacing 'awsContext' with something specific and meaningful
4646
outputChannel: vscode.OutputChannel
4747
resourceFetcher: ResourceFetcher
48-
functionNode: FunctionNodeBase // TODO: Consider replacing 'element'' with something specific and meaningful
48+
functionNode: LambdaFunctionNode
4949
}) {
5050
const logger: Logger = getLogger()
5151

@@ -136,7 +136,7 @@ function createMessageReceivedFunc({
136136
...restParams
137137
}: {
138138
// TODO: Consider passing lambdaClient: LambdaClient
139-
fn: FunctionNodeBase // TODO: Replace w/ invokeParams: {functionArn: string} // or Lambda.Types.InvocationRequest
139+
fn: LambdaFunctionNode // TODO: Replace w/ invokeParams: {functionArn: string} // or Lambda.Types.InvocationRequest
140140
outputChannel: vscode.OutputChannel
141141
resourceFetcher: ResourceFetcher
142142
resourcePath: string

src/lambda/explorer/cloudFormationNodes.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import { ErrorNode } from '../../shared/treeview/nodes/errorNode'
1818
import { PlaceholderNode } from '../../shared/treeview/nodes/placeholderNode'
1919
import { intersection, toArrayAsync, toMap, toMapAsync, updateInPlace } from '../../shared/utilities/collectionUtils'
2020
import { listCloudFormationStacks, listLambdaFunctions } from '../utils'
21-
import { FunctionNodeBase } from './functionNode'
21+
import { LambdaFunctionNode } from './lambdaFunctionNode'
22+
23+
export const CONTEXT_VALUE_CLOUDFORMATION_LAMBDA_FUNCTION = 'awsCloudFormationFunctionNode'
2224

2325
export class CloudFormationNode extends AWSTreeErrorHandlerNode {
2426
private readonly stackNodes: Map<string, CloudFormationStackNode>
@@ -53,7 +55,7 @@ export class CloudFormationNode extends AWSTreeErrorHandlerNode {
5355
}
5456

5557
export class CloudFormationStackNode extends AWSTreeErrorHandlerNode {
56-
private readonly functionNodes: Map<string, CloudFormationFunctionNode>
58+
private readonly functionNodes: Map<string, LambdaFunctionNode>
5759

5860
public constructor(
5961
public readonly parent: AWSTreeNodeBase,
@@ -64,7 +66,7 @@ export class CloudFormationStackNode extends AWSTreeErrorHandlerNode {
6466

6567
this.update(stackSummary)
6668
this.contextValue = 'awsCloudFormationNode'
67-
this.functionNodes = new Map<string, CloudFormationFunctionNode>()
69+
this.functionNodes = new Map<string, LambdaFunctionNode>()
6870
this.iconPath = {
6971
dark: vscode.Uri.file(ext.iconPaths.dark.cloudFormation),
7072
light: vscode.Uri.file(ext.iconPaths.light.cloudFormation)
@@ -79,7 +81,7 @@ export class CloudFormationStackNode extends AWSTreeErrorHandlerNode {
7981
return this.stackSummary.StackName
8082
}
8183

82-
public async getChildren(): Promise<(CloudFormationFunctionNode | PlaceholderNode)[]> {
84+
public async getChildren(): Promise<(LambdaFunctionNode | PlaceholderNode)[]> {
8385
await this.handleErrorProneOperation(
8486
async () => this.updateChildren(),
8587
localize('AWS.explorerNode.cloudFormation.error', 'Error loading CloudFormation resources')
@@ -119,7 +121,7 @@ export class CloudFormationStackNode extends AWSTreeErrorHandlerNode {
119121
this.functionNodes,
120122
intersection(resources, functions.keys()),
121123
key => this.functionNodes.get(key)!.update(functions.get(key)!),
122-
key => new CloudFormationFunctionNode(this, this.regionCode, functions.get(key)!)
124+
key => makeCloudFormationLambdaFunctionNode(this, this.regionCode, functions.get(key)!)
123125
)
124126
}
125127

@@ -137,13 +139,13 @@ export class CloudFormationStackNode extends AWSTreeErrorHandlerNode {
137139
}
138140
}
139141

140-
export class CloudFormationFunctionNode extends FunctionNodeBase {
141-
public constructor(
142-
public readonly parent: AWSTreeNodeBase,
143-
public readonly regionCode: string,
144-
configuration: Lambda.FunctionConfiguration
145-
) {
146-
super(parent, configuration)
147-
this.contextValue = 'awsCloudFormationFunctionNode'
148-
}
142+
function makeCloudFormationLambdaFunctionNode(
143+
parent: AWSTreeNodeBase,
144+
regionCode: string,
145+
configuration: Lambda.FunctionConfiguration
146+
): LambdaFunctionNode {
147+
const node = new LambdaFunctionNode(parent, regionCode, configuration)
148+
node.contextValue = CONTEXT_VALUE_CLOUDFORMATION_LAMBDA_FUNCTION
149+
150+
return node
149151
}

src/lambda/explorer/functionNode.ts renamed to src/lambda/explorer/lambdaFunctionNode.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import { Uri } from 'vscode'
99
import { ext } from '../../shared/extensionGlobals'
1010
import { AWSTreeNodeBase } from '../../shared/treeview/nodes/awsTreeNodeBase'
1111

12-
export abstract class FunctionNodeBase extends AWSTreeNodeBase {
13-
public abstract readonly regionCode: string
14-
15-
protected constructor(public readonly parent: AWSTreeNodeBase, public configuration: Lambda.FunctionConfiguration) {
12+
export class LambdaFunctionNode extends AWSTreeNodeBase {
13+
public constructor(
14+
public readonly parent: AWSTreeNodeBase,
15+
public readonly regionCode: string,
16+
public configuration: Lambda.FunctionConfiguration
17+
) {
1618
super('')
1719
this.update(configuration)
1820
this.iconPath = {

src/lambda/explorer/lambdaNodes.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import { AWSTreeNodeBase } from '../../shared/treeview/nodes/awsTreeNodeBase'
1515
import { ErrorNode } from '../../shared/treeview/nodes/errorNode'
1616
import { toArrayAsync, toMap, updateInPlace } from '../../shared/utilities/collectionUtils'
1717
import { listLambdaFunctions } from '../utils'
18-
import { FunctionNodeBase } from './functionNode'
18+
import { LambdaFunctionNode } from './lambdaFunctionNode'
19+
20+
export const CONTEXT_VALUE_LAMBDA_FUNCTION = 'awsRegionFunctionNode'
1921

2022
/**
2123
* An AWS Explorer node representing the Lambda Service.
@@ -53,18 +55,18 @@ export class LambdaNode extends AWSTreeErrorHandlerNode {
5355
this.functionNodes,
5456
functions.keys(),
5557
key => this.functionNodes.get(key)!.update(functions.get(key)!),
56-
key => new LambdaFunctionNode(this, this.regionCode, functions.get(key)!)
58+
key => makeLambdaFunctionNode(this, this.regionCode, functions.get(key)!)
5759
)
5860
}
5961
}
6062

61-
export class LambdaFunctionNode extends FunctionNodeBase {
62-
public constructor(
63-
public readonly parent: AWSTreeNodeBase,
64-
public readonly regionCode: string,
65-
configuration: Lambda.FunctionConfiguration
66-
) {
67-
super(parent, configuration)
68-
this.contextValue = 'awsRegionFunctionNode'
69-
}
63+
function makeLambdaFunctionNode(
64+
parent: AWSTreeNodeBase,
65+
regionCode: string,
66+
configuration: Lambda.FunctionConfiguration
67+
): LambdaFunctionNode {
68+
const node = new LambdaFunctionNode(parent, regionCode, configuration)
69+
node.contextValue = CONTEXT_VALUE_LAMBDA_FUNCTION
70+
71+
return node
7072
}

src/test/lambda/explorer/cloudFormationNodes.test.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ import * as assert from 'assert'
77
import { CloudFormation, Lambda } from 'aws-sdk'
88
import * as os from 'os'
99
import {
10-
CloudFormationFunctionNode,
1110
CloudFormationNode,
12-
CloudFormationStackNode
11+
CloudFormationStackNode,
12+
CONTEXT_VALUE_CLOUDFORMATION_LAMBDA_FUNCTION
1313
} from '../../../lambda/explorer/cloudFormationNodes'
14+
import { LambdaFunctionNode } from '../../../lambda/explorer/lambdaFunctionNode'
1415
import { CloudFormationClient } from '../../../shared/clients/cloudFormationClient'
1516
import { EcsClient } from '../../../shared/clients/ecsClient'
1617
import { LambdaClient } from '../../../shared/clients/lambdaClient'
1718
import { StsClient } from '../../../shared/clients/stsClient'
1819
import { ext } from '../../../shared/extensionGlobals'
20+
import { AWSTreeNodeBase } from '../../../shared/treeview/nodes/awsTreeNodeBase'
1921
import { ErrorNode } from '../../../shared/treeview/nodes/errorNode'
2022
import { PlaceholderNode } from '../../../shared/treeview/nodes/placeholderNode'
2123
import { MockCloudFormationClient } from '../../shared/clients/mockClients'
@@ -188,21 +190,28 @@ describe('CloudFormationStackNode', () => {
188190
const testNode: CloudFormationStackNode = generateTestNode()
189191

190192
const childNodes = await testNode.getChildren()
191-
assert(childNodes !== undefined)
193+
assert.ok(childNodes)
192194
assert.strictEqual(childNodes.length, 2)
193195

194-
assert(childNodes[0] instanceof CloudFormationFunctionNode)
195-
assert.strictEqual((childNodes[0] as CloudFormationFunctionNode).label, lambda1Name)
196-
197-
assert(childNodes[1] instanceof CloudFormationFunctionNode)
198-
assert.strictEqual((childNodes[1] as CloudFormationFunctionNode).label, lambda3Name)
196+
assertCloudFormationLambdaFunctionNode(childNodes[0], lambda1Name)
197+
assertCloudFormationLambdaFunctionNode(childNodes[1], lambda3Name)
199198
})
200199

201200
function generateTestNode(): CloudFormationStackNode {
202201
const parentNode = new TestAWSTreeNode('test node')
203202

204203
return new CloudFormationStackNode(parentNode, 'someregioncode', fakeStackSummary)
205204
}
205+
206+
function assertCloudFormationLambdaFunctionNode(actualNode: AWSTreeNodeBase, expectedLabel: string) {
207+
assert.ok(actualNode instanceof LambdaFunctionNode)
208+
assert.strictEqual(actualNode.label, expectedLabel, 'unexpected label for Lambda Function Node')
209+
assert.strictEqual(
210+
actualNode.contextValue,
211+
CONTEXT_VALUE_CLOUDFORMATION_LAMBDA_FUNCTION,
212+
'expected the node to have a CloudFormation contextValue'
213+
)
214+
}
206215
})
207216

208217
describe('CloudFormationNode', () => {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*!
2+
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as assert from 'assert'
7+
import { Lambda } from 'aws-sdk'
8+
import * as os from 'os'
9+
import { LambdaFunctionNode } from '../../../lambda/explorer/lambdaFunctionNode'
10+
import { ext } from '../../../shared/extensionGlobals'
11+
import { TestAWSTreeNode } from '../../shared/treeview/nodes/testAWSTreeNode'
12+
import { clearTestIconPaths, IconPath, setupTestIconPaths } from '../../shared/utilities/iconPathUtils'
13+
14+
describe('LambdaFunctionNode', () => {
15+
const parentNode = new TestAWSTreeNode('test node')
16+
let testNode: LambdaFunctionNode
17+
let fakeFunctionConfig: Lambda.FunctionConfiguration
18+
19+
before(async () => {
20+
setupTestIconPaths()
21+
fakeFunctionConfig = {
22+
FunctionName: 'testFunctionName',
23+
FunctionArn: 'testFunctionARN'
24+
}
25+
26+
testNode = new LambdaFunctionNode(parentNode, 'someregioncode', fakeFunctionConfig)
27+
})
28+
29+
after(async () => {
30+
clearTestIconPaths()
31+
})
32+
33+
it('instantiates without issue', async () => {
34+
assert.ok(testNode)
35+
})
36+
37+
it('initializes the parent node', async () => {
38+
assert.strictEqual(testNode.parent, parentNode, 'unexpected parent node')
39+
})
40+
41+
it('initializes the region code', async () => {
42+
assert.strictEqual(testNode.regionCode, 'someregioncode')
43+
})
44+
45+
it('initializes the label', async () => {
46+
assert.strictEqual(testNode.label, fakeFunctionConfig.FunctionName)
47+
})
48+
49+
it('initializes the functionName', async () => {
50+
assert.strictEqual(testNode.functionName, fakeFunctionConfig.FunctionName)
51+
})
52+
53+
it('initializes the tooltip', async () => {
54+
assert.strictEqual(
55+
testNode.tooltip,
56+
`${fakeFunctionConfig.FunctionName}${os.EOL}${fakeFunctionConfig.FunctionArn}`
57+
)
58+
})
59+
60+
it('initializes the icon', async () => {
61+
const iconPath = testNode.iconPath as IconPath
62+
63+
assert.strictEqual(iconPath.dark.path, ext.iconPaths.dark.lambda, 'Unexpected dark icon path')
64+
assert.strictEqual(iconPath.light.path, ext.iconPaths.light.lambda, 'Unexpected light icon path')
65+
})
66+
67+
it('has no children', async () => {
68+
const childNodes = await testNode.getChildren()
69+
assert.ok(childNodes)
70+
assert.strictEqual(childNodes.length, 0, 'Expected node to have no children')
71+
})
72+
})

src/test/lambda/explorer/lambdaNodes.test.ts

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,82 +5,21 @@
55

66
import * as assert from 'assert'
77
import { Lambda } from 'aws-sdk'
8-
import * as os from 'os'
9-
import { LambdaFunctionNode, LambdaNode } from '../../../lambda/explorer/lambdaNodes'
8+
import { LambdaFunctionNode } from '../../../lambda/explorer/lambdaFunctionNode'
9+
import { CONTEXT_VALUE_LAMBDA_FUNCTION, LambdaNode } from '../../../lambda/explorer/lambdaNodes'
1010
import { CloudFormationClient } from '../../../shared/clients/cloudFormationClient'
1111
import { EcsClient } from '../../../shared/clients/ecsClient'
1212
import { LambdaClient } from '../../../shared/clients/lambdaClient'
1313
import { StsClient } from '../../../shared/clients/stsClient'
1414
import { ext } from '../../../shared/extensionGlobals'
1515
import { ErrorNode } from '../../../shared/treeview/nodes/errorNode'
1616
import { MockLambdaClient } from '../../shared/clients/mockClients'
17-
import { TestAWSTreeNode } from '../../shared/treeview/nodes/testAWSTreeNode'
18-
import { clearTestIconPaths, IconPath, setupTestIconPaths } from '../../shared/utilities/iconPathUtils'
1917

2018
// TODO : Consolidate all asyncGenerator calls into a shared utility method
2119
async function* asyncGenerator<T>(items: T[]): AsyncIterableIterator<T> {
2220
yield* items
2321
}
2422

25-
describe('LambdaFunctionNode', () => {
26-
let fakeFunctionConfig: Lambda.FunctionConfiguration
27-
28-
before(async () => {
29-
setupTestIconPaths()
30-
fakeFunctionConfig = {
31-
FunctionName: 'testFunctionName',
32-
FunctionArn: 'testFunctionARN'
33-
}
34-
})
35-
36-
after(async () => {
37-
clearTestIconPaths()
38-
})
39-
40-
// Validates we tagged the node correctly
41-
it('initializes name and tooltip', async () => {
42-
const testNode = generateTestNode()
43-
44-
assert.strictEqual(testNode.label, fakeFunctionConfig.FunctionName)
45-
assert.strictEqual(
46-
testNode.tooltip,
47-
`${fakeFunctionConfig.FunctionName}${os.EOL}${fakeFunctionConfig.FunctionArn}`
48-
)
49-
})
50-
51-
it('initializes icon', async () => {
52-
const testNode = generateTestNode()
53-
54-
const iconPath = testNode.iconPath as IconPath
55-
56-
assert.strictEqual(iconPath.dark.path, ext.iconPaths.dark.lambda, 'Unexpected dark icon path')
57-
assert.strictEqual(iconPath.light.path, ext.iconPaths.light.lambda, 'Unexpected light icon path')
58-
})
59-
60-
// Validates we don't yield some unexpected value that our command triggers
61-
// don't recognize
62-
it('returns expected context value', async () => {
63-
const testNode = generateTestNode()
64-
65-
assert.strictEqual(testNode.contextValue, 'awsRegionFunctionNode')
66-
})
67-
68-
// Validates function nodes are leaves
69-
it('has no children', async () => {
70-
const testNode = generateTestNode()
71-
72-
const childNodes = await testNode.getChildren()
73-
assert(childNodes !== undefined)
74-
assert.strictEqual(childNodes.length, 0)
75-
})
76-
77-
function generateTestNode(): LambdaFunctionNode {
78-
const parentNode = new TestAWSTreeNode('test node')
79-
80-
return new LambdaFunctionNode(parentNode, 'someregioncode', fakeFunctionConfig)
81-
}
82-
})
83-
8423
describe('LambdaNode', () => {
8524
class FunctionNamesMockLambdaClient extends MockLambdaClient {
8625
public constructor(
@@ -147,6 +86,12 @@ describe('LambdaNode', () => {
14786
actualChildNode: LambdaFunctionNode | ErrorNode,
14887
expectedNodeText: string
14988
) {
89+
assert.strictEqual(
90+
actualChildNode.contextValue,
91+
CONTEXT_VALUE_LAMBDA_FUNCTION,
92+
'Expected child node to be marked as a Lambda Function'
93+
)
94+
15095
assert.strictEqual(
15196
'functionName' in actualChildNode,
15297
true,

0 commit comments

Comments
 (0)