33 * SPDX-License-Identifier: Apache-2.0
44 */
55
6- import { assertTelemetry , getMetrics , partialDeepCompare , TestFolder } from '../testUtil'
6+ import { getMetrics , partialDeepCompare , TestFolder } from '../testUtil'
77import assert from 'assert'
88import globals from '../../shared/extensionGlobals'
99import { CrashMonitoring , ExtInstance , crashMonitoringStateFactory } from '../../shared/crashMonitoring'
1010import { isCI } from '../../shared/vscode/env'
1111import { getLogger } from '../../shared/logger/logger'
1212import { SinonSandbox , createSandbox } from 'sinon'
13- import { fs , randomUUID } from '../../shared'
14- import path from 'path'
13+ import { randomUUID } from '../../shared'
1514
1615class TestCrashMonitoring extends CrashMonitoring {
1716 public constructor ( ...deps : ConstructorParameters < typeof CrashMonitoring > ) {
@@ -88,131 +87,133 @@ export const crashMonitoringTest = async () => {
8887 sandbox . restore ( )
8988 } )
9089
91- it ( 'graceful shutdown no metric emitted' , async function ( ) {
92- const exts = await makeTestExtensions ( 2 )
93-
94- await exts [ 0 ] . ext . start ( )
95- await awaitIntervals ( oneInterval ) // allow time to become primary checker
96- // There is no other active instance to report the issue
97- assertTelemetry ( 'session_end' , [ ] )
98-
99- // Ext 1 does a graceful shutdown
100- await exts [ 1 ] . ext . start ( )
101- await exts [ 1 ] . ext . shutdown ( )
102- await awaitIntervals ( oneInterval )
103- // Ext 1 did a graceful shutdown so no metric emitted
104- assertTelemetry ( 'session_end' , [ ] )
105- } )
106-
107- it ( 'single running instance crashes, so nothing is reported, but a new instaces appears and reports' , async function ( ) {
108- const exts = await makeTestExtensions ( 2 )
109-
110- await exts [ 0 ] . ext . start ( )
111- await exts [ 0 ] . ext . crash ( )
112- await awaitIntervals ( oneInterval )
113- // There is no other active instance to report the issue
114- assertTelemetry ( 'session_end' , [ ] )
115-
116- await exts [ 1 ] . ext . start ( )
117- await awaitIntervals ( oneInterval )
118- // Starting a new instance will detect the previously crashed one
119- assertCrashedExtensions ( [ exts [ 0 ] ] )
120- } )
121-
122- it ( 'multiple running instances start+crash at different times, but another instance always reports' , async function ( ) {
123- const latestCrashedExts : TestExtension [ ] = [ ]
124-
125- const exts = await makeTestExtensions ( 4 )
126-
127- await exts [ 0 ] . ext . start ( )
128- await awaitIntervals ( oneInterval )
129-
130- // start Ext 1 then crash it, Ext 0 finds the crash
131- await exts [ 1 ] . ext . start ( )
132- await exts [ 1 ] . ext . crash ( )
133- latestCrashedExts . push ( exts [ 1 ] )
134- await awaitIntervals ( oneInterval * 1 )
135-
136- assertCrashedExtensions ( latestCrashedExts )
137-
138- // start Ext 2 and crash Ext 0, Ext 2 is promoted to Primary checker
139- await exts [ 2 ] . ext . start ( )
140- await exts [ 0 ] . ext . crash ( )
141- latestCrashedExts . push ( exts [ 0 ] )
142- await awaitIntervals ( oneInterval * 1 )
143- assertCrashedExtensions ( latestCrashedExts )
144-
145- // Ext 3 starts, then crashes. Ext 2 reports the crash since it is the Primary checker
146- await exts [ 3 ] . ext . start ( )
147- await exts [ 3 ] . ext . crash ( )
148- latestCrashedExts . push ( exts [ 3 ] )
149- await awaitIntervals ( oneInterval * 1 )
150- assertCrashedExtensions ( latestCrashedExts )
151- } )
152-
153- it ( 'clears the state when a new os session is determined' , async function ( ) {
154- const exts = await makeTestExtensions ( 1 )
155-
156- // Start an extension then crash it
157- await exts [ 0 ] . ext . start ( )
158- await exts [ 0 ] . ext . crash ( )
159- await awaitIntervals ( oneInterval )
160- // There is no other active instance to report the issue
161- assertTelemetry ( 'session_end' , [ ] )
162-
163- // This extension clears the state due to it being stale, not reporting the previously crashed ext
164- const ext1 = await makeTestExtension ( 1 , { isStateStale : ( ) => Promise . resolve ( true ) } )
165- await ext1 . ext . start ( )
166- await awaitIntervals ( oneInterval * 1 )
167- assertCrashedExtensions ( [ ] )
168- } )
169-
170- it ( 'start the first extension, then start many subsequent ones and crash them all at once' , async function ( ) {
171- const latestCrashedExts : TestExtension [ ] = [ ]
172-
173- const extCount = 10
174- const exts = await makeTestExtensions ( extCount )
175- for ( let i = 0 ; i < extCount ; i ++ ) {
176- await exts [ i ] . ext . start ( )
177- }
178-
179- // Crash all exts except the 0th one
180- for ( let i = 1 ; i < extCount ; i ++ ) {
181- await exts [ i ] . ext . crash ( )
182- latestCrashedExts . push ( exts [ i ] )
183- }
184-
185- // Give some extra time since there is a lot of file i/o
186- await awaitIntervals ( oneInterval * 3 )
187-
188- assertCrashedExtensions ( latestCrashedExts )
189- } )
190-
191- it ( 'does not check for crashes when there is a time lag' , async function ( ) {
192- // This test handles the case for a users computer doing a sleep+wake and
193- // then a crash was incorrectly reported since a new heartbeat could not be sent in time
194-
195- // Load up a crash
196- const ext0 = await makeTestExtension ( 0 )
197- await ext0 . ext . start ( )
198- await ext0 . ext . crash ( )
199-
200- const ext1 = await makeTestExtension ( 1 )
201- // Indicate that we have a time lag, and until it returns false
202- // we will skip crash checking
203- const didLagStub = sandbox . stub ( ext1 . ext . getTimeLag ( ) , 'didLag' )
204- didLagStub . returns ( true )
205- await ext1 . ext . start ( )
206-
207- // Since we have a time lag the crash checker will not run
208- await awaitIntervals ( oneInterval * 2 )
209- assertCrashedExtensions ( [ ] )
210-
211- // Now that the time lag is true, we will check for a crash
212- didLagStub . returns ( false )
213- await awaitIntervals ( oneInterval )
214- assertCrashedExtensions ( [ ext0 ] )
215- } )
90+ // it('graceful shutdown no metric emitted', async function () {
91+ // const exts = await makeTestExtensions(2)
92+ //
93+ // await exts[0].ext.start()
94+ // await awaitIntervals(oneInterval) // allow time to become primary checker
95+ // // There is no other active instance to report the issue
96+ // assertTelemetry('session_end', [])
97+ //
98+ // // Ext 1 does a graceful shutdown
99+ // await exts[1].ext.start()
100+ // await exts[1].ext.shutdown()
101+ // await awaitIntervals(oneInterval)
102+ // // Ext 1 did a graceful shutdown so no metric emitted
103+ // assertTelemetry('session_end', [])
104+ // })
105+ //
106+ // it('single running instance crashes, so nothing is reported, but a new instaces appears and reports', async function () {
107+ // const exts = await makeTestExtensions(2)
108+ //
109+ // await exts[0].ext.start()
110+ // await exts[0].ext.crash()
111+ // await awaitIntervals(oneInterval)
112+ // // There is no other active instance to report the issue
113+ // assertTelemetry('session_end', [])
114+ //
115+ // await exts[1].ext.start()
116+ // await awaitIntervals(oneInterval)
117+ // // Starting a new instance will detect the previously crashed one
118+ // assertCrashedExtensions([exts[0]])
119+ // })
120+
121+ // for loop 50 times
122+ for ( let i = 0 ; i < 10 ; i ++ ) {
123+ it ( 'multiple running instances start+crash at different times, but another instance always reports' , async function ( ) {
124+ const latestCrashedExts : TestExtension [ ] = [ ]
125+
126+ const exts = await makeTestExtensions ( 4 )
127+
128+ await exts [ 0 ] . ext . start ( )
129+ await awaitIntervals ( oneInterval )
130+
131+ // start Ext 1 then crash it, Ext 0 finds the crash
132+ await exts [ 1 ] . ext . start ( )
133+ await exts [ 1 ] . ext . crash ( )
134+ latestCrashedExts . push ( exts [ 1 ] )
135+ await awaitIntervals ( oneInterval * 1 )
136+
137+ assertCrashedExtensions ( latestCrashedExts )
138+
139+ // start Ext 2 and crash Ext 0, Ext 2 is promoted to Primary checker
140+ await exts [ 2 ] . ext . start ( )
141+ await exts [ 0 ] . ext . crash ( )
142+ latestCrashedExts . push ( exts [ 0 ] )
143+ await awaitIntervals ( oneInterval * 1 )
144+ assertCrashedExtensions ( latestCrashedExts )
145+
146+ // Ext 3 starts, then crashes. Ext 2 reports the crash since it is the Primary checker
147+ await exts [ 3 ] . ext . start ( )
148+ await exts [ 3 ] . ext . crash ( )
149+ latestCrashedExts . push ( exts [ 3 ] )
150+ await awaitIntervals ( oneInterval * 1 )
151+ assertCrashedExtensions ( latestCrashedExts )
152+ } )
153+ }
154+ // it('clears the state when a new os session is determined', async function () {
155+ // const exts = await makeTestExtensions(1)
156+ //
157+ // // Start an extension then crash it
158+ // await exts[0].ext.start()
159+ // await exts[0].ext.crash()
160+ // await awaitIntervals(oneInterval)
161+ // // There is no other active instance to report the issue
162+ // assertTelemetry('session_end', [])
163+ //
164+ // // This extension clears the state due to it being stale, not reporting the previously crashed ext
165+ // const ext1 = await makeTestExtension(1, { isStateStale: () => Promise.resolve(true) })
166+ // await ext1.ext.start()
167+ // await awaitIntervals(oneInterval * 1)
168+ // assertCrashedExtensions([])
169+ // })
170+ //
171+ // it('start the first extension, then start many subsequent ones and crash them all at once', async function () {
172+ // const latestCrashedExts: TestExtension[] = []
173+ //
174+ // const extCount = 10
175+ // const exts = await makeTestExtensions(extCount)
176+ // for (let i = 0; i < extCount; i++) {
177+ // await exts[i].ext.start()
178+ // }
179+ //
180+ // // Crash all exts except the 0th one
181+ // for (let i = 1; i < extCount; i++) {
182+ // await exts[i].ext.crash()
183+ // latestCrashedExts.push(exts[i])
184+ // }
185+ //
186+ // // Give some extra time since there is a lot of file i/o
187+ // await awaitIntervals(oneInterval * 3)
188+ //
189+ // assertCrashedExtensions(latestCrashedExts)
190+ // })
191+ //
192+ // it('does not check for crashes when there is a time lag', async function () {
193+ // // This test handles the case for a users computer doing a sleep+wake and
194+ // // then a crash was incorrectly reported since a new heartbeat could not be sent in time
195+ //
196+ // // Load up a crash
197+ // const ext0 = await makeTestExtension(0)
198+ // await ext0.ext.start()
199+ // await ext0.ext.crash()
200+ //
201+ // const ext1 = await makeTestExtension(1)
202+ // // Indicate that we have a time lag, and until it returns false
203+ // // we will skip crash checking
204+ // const didLagStub = sandbox.stub(ext1.ext.getTimeLag(), 'didLag')
205+ // didLagStub.returns(true)
206+ // await ext1.ext.start()
207+ //
208+ // // Since we have a time lag the crash checker will not run
209+ // await awaitIntervals(oneInterval * 2)
210+ // assertCrashedExtensions([])
211+ //
212+ // // Now that the time lag is true, we will check for a crash
213+ // didLagStub.returns(false)
214+ // await awaitIntervals(oneInterval)
215+ // assertCrashedExtensions([ext0])
216+ // })
216217
217218 /**
218219 * Something like the following code can switch contexts early and the test will
@@ -250,11 +251,16 @@ export const crashMonitoringTest = async () => {
250251 [ ...allSessionEnds ] ,
251252 ( a , b ) => a . proxiedSessionId === b . proxiedSessionId
252253 )
253- assert . strictEqual ( deduplicatedSessionEnds . length , expectedExts . length )
254254
255255 expectedExts . sort ( ( a , b ) => a . metadata . sessionId . localeCompare ( b . metadata . sessionId ) )
256256 deduplicatedSessionEnds . sort ( ( a , b ) => a . proxiedSessionId ! . localeCompare ( b . proxiedSessionId ! ) )
257257
258+ assert . strictEqual (
259+ deduplicatedSessionEnds . length ,
260+ expectedExts . length ,
261+ `Actual: ${ JSON . stringify ( deduplicatedSessionEnds ) } , Expected: ${ expectedExts } `
262+ )
263+
258264 expectedExts . forEach ( ( ext , i ) => {
259265 partialDeepCompare ( deduplicatedSessionEnds [ i ] , {
260266 result : 'Failed' ,
@@ -268,31 +274,31 @@ export const crashMonitoringTest = async () => {
268274 return array . filter ( ( item , index , self ) => index === self . findIndex ( ( t ) => predicate ( item , t ) ) )
269275 }
270276
271- describe ( 'FileSystemState' , async function ( ) {
272- it ( 'ignores irrelevant files in state' , async function ( ) {
273- const state = await crashMonitoringStateFactory ( {
274- workDirPath : testFolder . path ,
275- isStateStale : ( ) => Promise . resolve ( false ) ,
276- sessionId : randomUUID ( ) ,
277- now : ( ) => globals . clock . Date . now ( ) ,
278- memento : globals . globalState ,
279- isDevMode : true ,
280- devLogger : getLogger ( ) ,
281- } )
282- const stateDirPath = state . stateDirPath
283-
284- assert . deepStrictEqual ( ( await fs . readdir ( stateDirPath ) ) . length , 0 )
285- await fs . writeFile ( path . join ( stateDirPath , 'ignoreMe.json' ) , '' )
286- await fs . mkdir ( path . join ( stateDirPath , 'ignoreMe' ) )
287- await state . sendHeartbeat ( ) // creates a relevant file in the state
288- assert . deepStrictEqual ( ( await fs . readdir ( stateDirPath ) ) . length , 3 )
289-
290- const result = await state . getAllExts ( )
291- assert . deepStrictEqual ( result . length , 1 )
292- } )
293- } )
277+ // describe('FileSystemState', async function () {
278+ // it('ignores irrelevant files in state', async function () {
279+ // const state = await crashMonitoringStateFactory({
280+ // workDirPath: testFolder.path,
281+ // isStateStale: () => Promise.resolve(false),
282+ // sessionId: randomUUID(),
283+ // now: () => globals.clock.Date.now(),
284+ // memento: globals.globalState,
285+ // isDevMode: true,
286+ // devLogger: getLogger(),
287+ // })
288+ // const stateDirPath = state.stateDirPath
289+ //
290+ // assert.deepStrictEqual((await fs.readdir(stateDirPath)).length, 0)
291+ // await fs.writeFile(path.join(stateDirPath, 'ignoreMe.json'), '')
292+ // await fs.mkdir(path.join(stateDirPath, 'ignoreMe'))
293+ // await state.sendHeartbeat() // creates a relevant file in the state
294+ // assert.deepStrictEqual((await fs.readdir(stateDirPath)).length, 3)
295+ //
296+ // const result = await state.getAllExts()
297+ // assert.deepStrictEqual(result.length, 1)
298+ // })
299+ // })
294300}
295301// This test is slow, so we only want to run it locally and not in CI. It will be run in the integ CI tests though.
296- ; ( isCI ( ) ? describe . skip : describe ) ( 'CrashReporting' , crashMonitoringTest )
302+ ; ( isCI ( ) ? describe : describe ) ( 'CrashReporting' , crashMonitoringTest )
297303
298304type TestExtension = { ext : TestCrashMonitoring ; metadata : ExtInstance }
0 commit comments