Skip to content

Commit dc31929

Browse files
committed
refactor to avoid circular dependency
1 parent 6e2b3e2 commit dc31929

File tree

8 files changed

+165
-111
lines changed

8 files changed

+165
-111
lines changed

packages/core/src/awsService/ec2/commands.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
import { Ec2Node } from './explorer/ec2ParentNode'
77
import { SafeEc2Instance, Ec2Client } from '../../shared/clients/ec2Client'
88
import { Ec2ConnectionManagerMap } from './activation'
9-
import { getConnectionManager } from './utils'
109
import { copyToClipboard } from '../../shared/utilities/messages'
1110
import { getAwsConsoleUrl } from '../../shared/awsConsole'
1211
import { showRegionPrompter } from '../../auth/utils'
1312
import { openUrl } from '../../shared/utilities/vsCodeUtils'
1413
import { Ec2Prompter, Ec2Selection, instanceFilter } from './prompter'
1514
import { Ec2InstanceNode } from './explorer/ec2InstanceNode'
15+
import { Ec2ConnectionManager } from './model'
1616

1717
export async function openTerminal(connectionManagers: Ec2ConnectionManagerMap, node?: Ec2Node) {
1818
const selection = await getSelection(node)
@@ -61,3 +61,16 @@ async function getSelection(node?: Ec2Node, filter?: instanceFilter): Promise<Ec
6161
export async function copyInstanceId(instanceId: string): Promise<void> {
6262
await copyToClipboard(instanceId, 'Id')
6363
}
64+
65+
export async function getConnectionManager(
66+
connectionManagers: Ec2ConnectionManagerMap,
67+
selection: Ec2Selection
68+
): Promise<Ec2ConnectionManager> {
69+
if (connectionManagers.has(selection.region)) {
70+
return connectionManagers.get(selection.region)!
71+
} else {
72+
const newConnectionManager = new Ec2ConnectionManager(selection.region)
73+
connectionManagers.set(selection.region, newConnectionManager)
74+
return newConnectionManager
75+
}
76+
}

packages/core/src/awsService/ec2/explorer/ec2InstanceNode.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import { SafeEc2Instance } from '../../../shared/clients/ec2Client'
1010
import globals from '../../../shared/extensionGlobals'
1111
import { getIconCode } from '../utils'
1212
import { Ec2Selection } from '../prompter'
13-
import { Ec2ParentNode } from './ec2ParentNode'
13+
import { Ec2Node, Ec2ParentNode } from './ec2ParentNode'
1414
import { EC2 } from 'aws-sdk'
15+
import { getLogger } from '../../../shared'
1516

1617
export const Ec2InstanceRunningContext = 'awsEc2RunningNode'
1718
export const Ec2InstanceStoppedContext = 'awsEc2StoppedNode'
@@ -100,3 +101,14 @@ export class Ec2InstanceNode extends AWSTreeNodeBase implements AWSResourceNode
100101
await vscode.commands.executeCommand('aws.refreshAwsExplorerNode', this)
101102
}
102103
}
104+
105+
export async function refreshExplorerNode(node?: Ec2Node) {
106+
if (node) {
107+
const n = node instanceof Ec2InstanceNode ? node.parent : node
108+
try {
109+
await n.refreshNode()
110+
} catch (e) {
111+
getLogger().error('refreshNode failed: %s', (e as Error).message)
112+
}
113+
}
114+
}

packages/core/src/awsService/ec2/prompter.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { isValidResponse } from '../../shared/wizards/wizard'
1010
import { CancellationError } from '../../shared/utilities/timeoutUtils'
1111
import { AsyncCollection } from '../../shared/utilities/asyncCollection'
1212
import { getIconCode } from './utils'
13+
import { Ec2Node } from './explorer/ec2ParentNode'
14+
import { Ec2InstanceNode } from './explorer/ec2InstanceNode'
1315

1416
export type instanceFilter = (instance: SafeEc2Instance) => boolean
1517
export interface Ec2Selection {
@@ -72,3 +74,9 @@ export class Ec2Prompter {
7274
)
7375
}
7476
}
77+
78+
export async function getSelection(node?: Ec2Node, filter?: instanceFilter): Promise<Ec2Selection> {
79+
const prompter = new Ec2Prompter(filter)
80+
const selection = node && node instanceof Ec2InstanceNode ? node.toSelection() : await prompter.promptUser()
81+
return selection
82+
}

packages/core/src/awsService/ec2/utils.ts

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@
44
*/
55

66
import { SSM } from 'aws-sdk'
7-
import { getLogger } from '../../shared'
87
import { SafeEc2Instance } from '../../shared/clients/ec2Client'
98
import { copyToClipboard } from '../../shared/utilities/messages'
10-
import { Ec2ConnectionManagerMap } from './activation'
11-
import { Ec2InstanceNode } from './explorer/ec2InstanceNode'
12-
import { Ec2Node } from './explorer/ec2ParentNode'
13-
import { Ec2ConnectionManager } from './model'
14-
import { Ec2Prompter, Ec2Selection, instanceFilter } from './prompter'
9+
import { Ec2Selection } from './prompter'
1510
import { sshLogFileLocation } from '../../shared/sshConfig'
1611

1712
export function getIconCode(instance: SafeEc2Instance) {
@@ -26,36 +21,6 @@ export function getIconCode(instance: SafeEc2Instance) {
2621
return 'loading~spin'
2722
}
2823

29-
export async function refreshExplorerNode(node?: Ec2Node) {
30-
if (node) {
31-
const n = node instanceof Ec2InstanceNode ? node.parent : node
32-
try {
33-
await n.refreshNode()
34-
} catch (e) {
35-
getLogger().error('refreshNode failed: %s', (e as Error).message)
36-
}
37-
}
38-
}
39-
40-
export async function getSelection(node?: Ec2Node, filter?: instanceFilter): Promise<Ec2Selection> {
41-
const prompter = new Ec2Prompter(filter)
42-
const selection = node && node instanceof Ec2InstanceNode ? node.toSelection() : await prompter.promptUser()
43-
return selection
44-
}
45-
46-
export async function getConnectionManager(
47-
connectionManagers: Ec2ConnectionManagerMap,
48-
selection: Ec2Selection
49-
): Promise<Ec2ConnectionManager> {
50-
if (connectionManagers.has(selection.region)) {
51-
return connectionManagers.get(selection.region)!
52-
} else {
53-
const newConnectionManager = new Ec2ConnectionManager(selection.region)
54-
connectionManagers.set(selection.region, newConnectionManager)
55-
return newConnectionManager
56-
}
57-
}
58-
5924
export async function copyInstanceId(instanceId: string): Promise<void> {
6025
await copyToClipboard(instanceId, 'Id')
6126
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import assert from 'assert'
7+
import { Ec2ConnectionManagerMap } from '../../../awsService/ec2/activation'
8+
import { getConnectionManager } from '../../../awsService/ec2/commands'
9+
import { Ec2ConnectionManager } from '../../../awsService/ec2/model'
10+
import { Ec2Selection } from '../../../awsService/ec2/prompter'
11+
12+
describe('getConnectionManager', async function () {
13+
let connectionManagers: Ec2ConnectionManagerMap
14+
15+
beforeEach(function () {
16+
connectionManagers = new Map<string, Ec2ConnectionManager>()
17+
})
18+
19+
it('only creates new connection managers once for each region ', async function () {
20+
const fakeSelection: Ec2Selection = {
21+
region: 'region-1',
22+
instanceId: 'fake-id',
23+
}
24+
25+
const cm = await getConnectionManager(connectionManagers, fakeSelection)
26+
assert.strictEqual(connectionManagers.size, 1)
27+
28+
await cm.addActiveSession('sessionId', 'instanceId')
29+
30+
const cm2 = await getConnectionManager(connectionManagers, fakeSelection)
31+
32+
assert.strictEqual(cm2.isConnectedTo('instanceId'), true)
33+
})
34+
})

packages/core/src/test/awsService/ec2/explorer/ec2InstanceNode.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
import * as sinon from 'sinon'
67
import assert from 'assert'
78
import {
89
Ec2InstanceNode,
910
Ec2InstancePendingContext,
1011
Ec2InstanceRunningContext,
1112
Ec2InstanceStoppedContext,
13+
refreshExplorerNode,
1214
} from '../../../../awsService/ec2/explorer/ec2InstanceNode'
1315
import { Ec2Client, SafeEc2Instance, getNameOfInstance } from '../../../../shared/clients/ec2Client'
1416
import { Ec2ParentNode } from '../../../../awsService/ec2/explorer/ec2ParentNode'
17+
import { DefaultAwsContext } from '../../../../shared'
1518

1619
describe('ec2InstanceNode', function () {
1720
let testNode: Ec2InstanceNode
@@ -92,4 +95,51 @@ describe('ec2InstanceNode', function () {
9295
testNode.updateInstance(newIdInstance)
9396
assert.strictEqual(testNode.getStatus(), newStatus)
9497
})
98+
99+
describe('refreshExplorerNode', function () {
100+
let testInstance: SafeEc2Instance
101+
let testParentNode: Ec2ParentNode
102+
let testClient: Ec2Client
103+
let testNode: Ec2InstanceNode
104+
105+
before(function () {
106+
sinon.stub(DefaultAwsContext.prototype, 'getCredentialAccountId')
107+
testInstance = {
108+
InstanceId: 'testId',
109+
Tags: [
110+
{
111+
Key: 'Name',
112+
Value: 'testName',
113+
},
114+
],
115+
LastSeenStatus: 'running',
116+
}
117+
testClient = new Ec2Client('')
118+
testParentNode = new Ec2ParentNode('fake-region', 'testPartition', testClient)
119+
testNode = new Ec2InstanceNode(testParentNode, testClient, 'testRegion', 'testPartition', testInstance)
120+
})
121+
122+
after(function () {
123+
sinon.restore()
124+
})
125+
126+
it('refreshes only parent node', async function () {
127+
const testParentNode = new Ec2ParentNode('fake-region', 'testPartition', testClient)
128+
const parentRefresh = sinon.stub(Ec2ParentNode.prototype, 'refreshNode')
129+
const childRefresh = sinon.stub(Ec2InstanceNode.prototype, 'refreshNode')
130+
131+
await refreshExplorerNode(testNode)
132+
sinon.assert.calledOn(parentRefresh, testParentNode)
133+
134+
parentRefresh.resetHistory()
135+
136+
await refreshExplorerNode(testParentNode)
137+
sinon.assert.calledOn(parentRefresh, testParentNode)
138+
139+
sinon.assert.notCalled(childRefresh)
140+
141+
parentRefresh.restore()
142+
childRefresh.restore()
143+
})
144+
})
95145
})

packages/core/src/test/awsService/ec2/prompter.test.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
import assert from 'assert'
6-
import { Ec2Prompter, instanceFilter } from '../../../awsService/ec2/prompter'
7-
import { SafeEc2Instance } from '../../../shared/clients/ec2Client'
6+
import * as sinon from 'sinon'
7+
import { Ec2Prompter, getSelection, instanceFilter } from '../../../awsService/ec2/prompter'
8+
import { Ec2Client, SafeEc2Instance } from '../../../shared/clients/ec2Client'
89
import { RegionSubmenuResponse } from '../../../shared/ui/common/regionSubmenu'
910
import { Ec2Selection } from '../../../awsService/ec2/prompter'
1011
import { AsyncCollection } from '../../../shared/utilities/asyncCollection'
1112
import { intoCollection } from '../../../shared/utilities/collectionUtils'
1213
import { DataQuickPickItem } from '../../../shared/ui/pickerPrompter'
14+
import { Ec2ParentNode } from '../../../awsService/ec2/explorer/ec2ParentNode'
15+
import { Ec2InstanceNode } from '../../../awsService/ec2/explorer/ec2InstanceNode'
1316

1417
describe('Ec2Prompter', async function () {
1518
class MockEc2Prompter extends Ec2Prompter {
@@ -183,4 +186,43 @@ describe('Ec2Prompter', async function () {
183186
assert.deepStrictEqual(items, expected)
184187
})
185188
})
189+
190+
describe('getSelection', async function () {
191+
it('uses node when passed', async function () {
192+
const testInstance = {
193+
InstanceId: 'testId',
194+
Tags: [
195+
{
196+
Key: 'Name',
197+
Value: 'testName',
198+
},
199+
],
200+
LastSeenStatus: 'running',
201+
}
202+
const testClient = new Ec2Client('')
203+
const testParentNode = new Ec2ParentNode('fake-region', 'testPartition', testClient)
204+
const testNode = new Ec2InstanceNode(
205+
testParentNode,
206+
testClient,
207+
'testRegion',
208+
'testPartition',
209+
testInstance
210+
)
211+
212+
const prompterStub = sinon.stub(Ec2Prompter.prototype, 'promptUser')
213+
const result = await getSelection(testNode)
214+
215+
assert.strictEqual(result.instanceId, testNode.toSelection().instanceId)
216+
assert.strictEqual(result.region, testNode.toSelection().region)
217+
sinon.assert.notCalled(prompterStub)
218+
prompterStub.restore()
219+
})
220+
221+
it('prompts user when no node is passed', async function () {
222+
const prompterStub = sinon.stub(Ec2Prompter.prototype, 'promptUser')
223+
await getSelection()
224+
sinon.assert.calledOnce(prompterStub)
225+
prompterStub.restore()
226+
})
227+
})
186228
})

packages/core/src/test/awsService/ec2/utils.test.ts

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@
66
import assert from 'assert'
77
import * as sinon from 'sinon'
88
import { Ec2Client, SafeEc2Instance } from '../../../shared/clients/ec2Client'
9-
import { getConnectionManager, getIconCode, getSelection, refreshExplorerNode } from '../../../awsService/ec2/utils'
9+
import { getIconCode } from '../../../awsService/ec2/utils'
1010
import { Ec2InstanceNode } from '../../../awsService/ec2/explorer/ec2InstanceNode'
1111
import { Ec2ParentNode } from '../../../awsService/ec2/explorer/ec2ParentNode'
12-
import { Ec2Prompter, Ec2Selection } from '../../../awsService/ec2/prompter'
13-
import { Ec2ConnectionManagerMap } from '../../../awsService/ec2/activation'
14-
import { Ec2ConnectionManager } from '../../../awsService/ec2/model'
1512
import { DefaultAwsContext } from '../../../shared'
1613

1714
describe('utils', async function () {
@@ -70,71 +67,4 @@ describe('utils', async function () {
7067
assert.strictEqual(getIconCode(stoppingInstance), 'loading~spin')
7168
})
7269
})
73-
74-
describe('refreshExplorerNode', function () {
75-
after(function () {
76-
sinon.restore()
77-
})
78-
79-
it('refreshes only parent node', async function () {
80-
const parentRefresh = sinon.stub(Ec2ParentNode.prototype, 'refreshNode')
81-
const childRefresh = sinon.stub(Ec2InstanceNode.prototype, 'refreshNode')
82-
83-
await refreshExplorerNode(testNode)
84-
sinon.assert.calledOn(parentRefresh, testParentNode)
85-
86-
parentRefresh.resetHistory()
87-
88-
await refreshExplorerNode(testParentNode)
89-
sinon.assert.calledOn(parentRefresh, testParentNode)
90-
91-
sinon.assert.notCalled(childRefresh)
92-
93-
parentRefresh.restore()
94-
childRefresh.restore()
95-
})
96-
})
97-
98-
describe('getSelection', async function () {
99-
it('uses node when passed', async function () {
100-
const prompterStub = sinon.stub(Ec2Prompter.prototype, 'promptUser')
101-
const result = await getSelection(testNode)
102-
103-
assert.strictEqual(result.instanceId, testNode.toSelection().instanceId)
104-
assert.strictEqual(result.region, testNode.toSelection().region)
105-
sinon.assert.notCalled(prompterStub)
106-
prompterStub.restore()
107-
})
108-
109-
it('prompts user when no node is passed', async function () {
110-
const prompterStub = sinon.stub(Ec2Prompter.prototype, 'promptUser')
111-
await getSelection()
112-
sinon.assert.calledOnce(prompterStub)
113-
prompterStub.restore()
114-
})
115-
})
116-
117-
describe('getConnectionManager', async function () {
118-
let connectionManagers: Ec2ConnectionManagerMap
119-
120-
beforeEach(function () {
121-
connectionManagers = new Map<string, Ec2ConnectionManager>()
122-
})
123-
124-
it('only creates new connection managers once for each region ', async function () {
125-
const fakeSelection: Ec2Selection = {
126-
region: 'region-1',
127-
instanceId: 'fake-id',
128-
}
129-
130-
const cm = await getConnectionManager(connectionManagers, fakeSelection)
131-
assert.strictEqual(connectionManagers.size, 1)
132-
133-
await cm.addActiveSession('sessionId', 'instanceId')
134-
135-
const cm2 = await getConnectionManager(connectionManagers, fakeSelection)
136-
137-
assert.strictEqual(cm2.isConnectedTo('instanceId'), true)
138-
})
139-
})
14070
})

0 commit comments

Comments
 (0)