Skip to content

Commit 96b32a5

Browse files
Merge master into feature/emr
2 parents 041ec9e + 2efb7a2 commit 96b32a5

File tree

4 files changed

+85
-35
lines changed

4 files changed

+85
-35
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export class Ec2InstanceNode extends AWSTreeNodeBase implements AWSResourceNode
2929
public readonly instance: SafeEc2Instance
3030
) {
3131
super('')
32+
this.parent.addChild(this)
3233
this.updateInstance(instance)
3334
this.id = this.InstanceId
3435
}
@@ -41,7 +42,7 @@ export class Ec2InstanceNode extends AWSTreeNodeBase implements AWSResourceNode
4142
this.tooltip = `${this.name}\n${this.InstanceId}\n${this.instance.LastSeenStatus}\n${this.arn}`
4243

4344
if (this.isPending()) {
44-
this.parent.pollingSet.start(this.InstanceId)
45+
this.parent.trackPendingNode(this.InstanceId)
4546
}
4647
}
4748

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ export class Ec2ParentNode extends AWSTreeNodeBase {
4141
})
4242
}
4343

44+
public trackPendingNode(instanceId: string) {
45+
if (!this.ec2InstanceNodes.has(instanceId)) {
46+
throw new Error(`Attempt to track ec2 node ${instanceId} that isn't a child`)
47+
}
48+
this.pollingSet.start(instanceId)
49+
}
50+
4451
public async updateChildren(): Promise<void> {
4552
const ec2Instances = await (await this.ec2Client.getInstances()).toMap((instance) => instance.InstanceId)
4653
updateInPlace(
@@ -52,9 +59,18 @@ export class Ec2ParentNode extends AWSTreeNodeBase {
5259
)
5360
}
5461

62+
public getInstanceNode(instanceId: string): Ec2InstanceNode {
63+
const childNode = this.ec2InstanceNodes.get(instanceId)
64+
if (childNode) {
65+
return childNode
66+
} else {
67+
throw new Error(`Node with id ${instanceId} from polling set not found`)
68+
}
69+
}
70+
5571
private async updatePendingNodes() {
5672
for (const instanceId of this.pollingSet.values()) {
57-
const childNode = this.ec2InstanceNodes.get(instanceId)!
73+
const childNode = this.getInstanceNode(instanceId)
5874
await this.updatePendingNode(childNode)
5975
}
6076
}
@@ -71,6 +87,10 @@ export class Ec2ParentNode extends AWSTreeNodeBase {
7187
this.ec2InstanceNodes = new Map<string, Ec2InstanceNode>()
7288
}
7389

90+
public addChild(node: Ec2InstanceNode) {
91+
this.ec2InstanceNodes.set(node.InstanceId, node)
92+
}
93+
7494
public async refreshNode(): Promise<void> {
7595
await this.clearChildren()
7696
await vscode.commands.executeCommand('aws.refreshAwsExplorerNode', this)

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
} from '../../../../awsService/ec2/explorer/ec2InstanceNode'
1313
import { Ec2Client, SafeEc2Instance, getNameOfInstance } from '../../../../shared/clients/ec2Client'
1414
import { Ec2ParentNode } from '../../../../awsService/ec2/explorer/ec2ParentNode'
15+
import * as sinon from 'sinon'
16+
import { PollingSet } from '../../../../shared/utilities/pollingSet'
1517

1618
describe('ec2InstanceNode', function () {
1719
let testNode: Ec2InstanceNode
@@ -30,12 +32,16 @@ describe('ec2InstanceNode', function () {
3032
],
3133
LastSeenStatus: 'running',
3234
}
35+
sinon.stub(Ec2InstanceNode.prototype, 'updateStatus')
36+
// Don't want to be polling here, that is tested in ../ec2ParentNode.test.ts
37+
// disabled here for convenience (avoiding race conditions with timeout)
38+
sinon.stub(PollingSet.prototype, 'start')
3339
const testClient = new Ec2Client('')
3440
const testParentNode = new Ec2ParentNode(testRegion, testPartition, testClient)
3541
testNode = new Ec2InstanceNode(testParentNode, testClient, 'testRegion', 'testPartition', testInstance)
3642
})
3743

38-
this.beforeEach(function () {
44+
beforeEach(function () {
3945
testNode.updateInstance(testInstance)
4046
})
4147

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

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,14 @@ import { EC2 } from 'aws-sdk'
1717
import { AsyncCollection } from '../../../../shared/utilities/asyncCollection'
1818
import * as FakeTimers from '@sinonjs/fake-timers'
1919
import { installFakeClock } from '../../../testUtil'
20-
import { PollingSet } from '../../../../shared/utilities/pollingSet'
2120

2221
describe('ec2ParentNode', function () {
2322
let testNode: Ec2ParentNode
24-
let defaultInstances: SafeEc2Instance[]
2523
let client: Ec2Client
2624
let getInstanceStub: sinon.SinonStub<[filters?: EC2.Filter[] | undefined], Promise<AsyncCollection<EC2.Instance>>>
2725
let clock: FakeTimers.InstalledClock
2826
let refreshStub: sinon.SinonStub<[], Promise<void>>
29-
let clearTimerStub: sinon.SinonStub<[], void>
30-
27+
let statusUpdateStub: sinon.SinonStub<[status: string], Promise<string>>
3128
const testRegion = 'testRegion'
3229
const testPartition = 'testPartition'
3330

@@ -45,36 +42,19 @@ describe('ec2ParentNode', function () {
4542
client = new Ec2Client(testRegion)
4643
clock = installFakeClock()
4744
refreshStub = sinon.stub(Ec2InstanceNode.prototype, 'refreshNode')
48-
clearTimerStub = sinon.stub(PollingSet.prototype, 'clearTimer')
49-
defaultInstances = [
50-
{ Name: 'firstOne', InstanceId: '0', LastSeenStatus: 'running' },
51-
{ Name: 'secondOne', InstanceId: '1', LastSeenStatus: 'running' },
52-
]
45+
statusUpdateStub = sinon.stub(Ec2Client.prototype, 'getInstanceStatus')
5346
})
5447

5548
beforeEach(function () {
5649
getInstanceStub = sinon.stub(Ec2Client.prototype, 'getInstances')
57-
defaultInstances = [
58-
{ Name: 'firstOne', InstanceId: '0', LastSeenStatus: 'running' },
59-
{ Name: 'secondOne', InstanceId: '1', LastSeenStatus: 'stopped' },
60-
]
61-
62-
getInstanceStub.callsFake(async () =>
63-
intoCollection(
64-
defaultInstances.map((instance) => ({
65-
InstanceId: instance.InstanceId,
66-
Tags: [{ Key: 'Name', Value: instance.Name }],
67-
}))
68-
)
69-
)
70-
7150
testNode = new Ec2ParentNode(testRegion, testPartition, client)
7251
refreshStub.resetHistory()
73-
clearTimerStub.resetHistory()
7452
})
7553

7654
afterEach(function () {
7755
getInstanceStub.restore()
56+
testNode.pollingSet.clear()
57+
testNode.pollingSet.clearTimer()
7858
})
7959

8060
after(function () {
@@ -91,10 +71,14 @@ describe('ec2ParentNode', function () {
9171
})
9272

9373
it('has instance child nodes', async function () {
94-
getInstanceStub.resolves(mapToInstanceCollection(defaultInstances))
74+
const instances = [
75+
{ Name: 'firstOne', InstanceId: '0', LastSeenStatus: 'running' },
76+
{ Name: 'secondOne', InstanceId: '1', LastSeenStatus: 'stopped' },
77+
]
78+
getInstanceStub.resolves(mapToInstanceCollection(instances))
9579
const childNodes = await testNode.getChildren()
9680

97-
assert.strictEqual(childNodes.length, defaultInstances.length, 'Unexpected child count')
81+
assert.strictEqual(childNodes.length, instances.length, 'Unexpected child count')
9882

9983
childNodes.forEach((node) =>
10084
assert.ok(node instanceof Ec2InstanceNode, 'Expected child node to be Ec2InstanceNode')
@@ -151,14 +135,13 @@ describe('ec2ParentNode', function () {
151135
]
152136

153137
getInstanceStub.resolves(mapToInstanceCollection(instances))
154-
155138
await testNode.updateChildren()
156139
assert.strictEqual(testNode.pollingSet.size, 1)
157140
getInstanceStub.restore()
158141
})
159142

160143
it('does not refresh explorer when timer goes off if status unchanged', async function () {
161-
const statusUpdateStub = sinon.stub(Ec2Client.prototype, 'getInstanceStatus').resolves('pending')
144+
statusUpdateStub = statusUpdateStub.resolves('pending')
162145
const instances = [
163146
{ Name: 'firstOne', InstanceId: '0', LastSeenStatus: 'pending' },
164147
{ Name: 'secondOne', InstanceId: '1', LastSeenStatus: 'stopped' },
@@ -170,16 +153,56 @@ describe('ec2ParentNode', function () {
170153
await testNode.updateChildren()
171154
await clock.tickAsync(6000)
172155
sinon.assert.notCalled(refreshStub)
173-
statusUpdateStub.restore()
174156
getInstanceStub.restore()
175157
})
176158

177159
it('does refresh explorer when timer goes and status changed', async function () {
160+
statusUpdateStub = statusUpdateStub.resolves('running')
161+
const instances = [{ Name: 'firstOne', InstanceId: '0', LastSeenStatus: 'pending' }]
162+
163+
getInstanceStub.resolves(mapToInstanceCollection(instances))
164+
await testNode.updateChildren()
165+
178166
sinon.assert.notCalled(refreshStub)
179-
const statusUpdateStub = sinon.stub(Ec2Client.prototype, 'getInstanceStatus').resolves('running')
180-
testNode.pollingSet.add('0')
181167
await clock.tickAsync(6000)
182168
sinon.assert.called(refreshStub)
183-
statusUpdateStub.restore()
169+
})
170+
171+
it('returns the node when in the map', async function () {
172+
const instances = [{ Name: 'firstOne', InstanceId: 'node1', LastSeenStatus: 'pending' }]
173+
174+
getInstanceStub.resolves(mapToInstanceCollection(instances))
175+
await testNode.updateChildren()
176+
const node = testNode.getInstanceNode('node1')
177+
assert.strictEqual(node.InstanceId, instances[0].InstanceId)
178+
getInstanceStub.restore()
179+
})
180+
181+
it('throws error when node not in map', async function () {
182+
const instances = [{ Name: 'firstOne', InstanceId: 'node1', LastSeenStatus: 'pending' }]
183+
184+
getInstanceStub.resolves(mapToInstanceCollection(instances))
185+
await testNode.updateChildren()
186+
assert.throws(() => testNode.getInstanceNode('node2'))
187+
getInstanceStub.restore()
188+
})
189+
190+
it('adds node to polling set when asked to track it', async function () {
191+
const instances = [{ Name: 'firstOne', InstanceId: 'node1', LastSeenStatus: 'pending' }]
192+
193+
getInstanceStub.resolves(mapToInstanceCollection(instances))
194+
await testNode.updateChildren()
195+
testNode.trackPendingNode('node1')
196+
assert.strictEqual(testNode.pollingSet.size, 1)
197+
getInstanceStub.restore()
198+
})
199+
200+
it('throws error when asked to track non-child node', async function () {
201+
const instances = [{ Name: 'firstOne', InstanceId: 'node1', LastSeenStatus: 'pending' }]
202+
203+
getInstanceStub.resolves(mapToInstanceCollection(instances))
204+
await testNode.updateChildren()
205+
assert.throws(() => testNode.trackPendingNode('node2'))
206+
getInstanceStub.restore()
184207
})
185208
})

0 commit comments

Comments
 (0)