diff --git a/packages/electron/src/main/modules/BacktraceMainElectronModule.ts b/packages/electron/src/main/modules/BacktraceMainElectronModule.ts index 5ca9465e..7f87950f 100644 --- a/packages/electron/src/main/modules/BacktraceMainElectronModule.ts +++ b/packages/electron/src/main/modules/BacktraceMainElectronModule.ts @@ -149,7 +149,9 @@ export class BacktraceMainElectronModule implements BacktraceModule { ) { // Sort crashes and sessions by timestamp descending const crashes = crashReporter.getUploadedReports().sort((a, b) => b.date.getTime() - a.date.getTime()); - const previousSessions = session.getPreviousSessions().sort((a, b) => b.timestamp - a.timestamp); + const previousSessions = session + .getPreviousSessions() + .sort((a, b) => b.sessionId.timestamp - a.sessionId.timestamp); for (const crash of crashes) { const rxid = this.getCrashRxid(crash.id); @@ -159,7 +161,7 @@ export class BacktraceMainElectronModule implements BacktraceModule { try { // Get first session that happened before the crash - const session = previousSessions.find((p) => p.timestamp < crash.date.getTime()); + const session = previousSessions.find((p) => p.sessionId.timestamp < crash.date.getTime()); // If there is no such session, there won't be any other sessions if (!session) { break; diff --git a/packages/node/tests/breadcrumbs/FileBreadcrumbsStorage.spec.ts b/packages/node/tests/breadcrumbs/FileBreadcrumbsStorage.spec.ts index 2fc66bb2..acbf1693 100644 --- a/packages/node/tests/breadcrumbs/FileBreadcrumbsStorage.spec.ts +++ b/packages/node/tests/breadcrumbs/FileBreadcrumbsStorage.spec.ts @@ -34,7 +34,7 @@ const nextTick = promisify(process.nextTick); describe('FileBreadcrumbsStorage', () => { it('should return added breadcrumbs', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -108,7 +108,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return added breadcrumbs in two attachments', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -190,7 +190,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return no more than maximumBreadcrumbs breadcrumbs', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -262,7 +262,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return breadcrumbs up to the json size', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -330,7 +330,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return attachments with a valid name from getAttachments', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -374,7 +374,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return attachments with a valid name from getAttachmentProviders', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { diff --git a/packages/react-native/tests/storage/FileBreadcrumbsStorage.spec.ts b/packages/react-native/tests/storage/FileBreadcrumbsStorage.spec.ts index 63a194db..a1bb2140 100644 --- a/packages/react-native/tests/storage/FileBreadcrumbsStorage.spec.ts +++ b/packages/react-native/tests/storage/FileBreadcrumbsStorage.spec.ts @@ -25,7 +25,7 @@ const nextTick = promisify(process.nextTick); describe('FileBreadcrumbsStorage', () => { it('should return added breadcrumbs', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -99,7 +99,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return added breadcrumbs in two attachments', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -181,7 +181,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return no more than maximumBreadcrumbs breadcrumbs', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -253,7 +253,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return breadcrumbs up to the json size', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -322,7 +322,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return attachments with a valid name from getAttachments', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { @@ -366,7 +366,7 @@ describe('FileBreadcrumbsStorage', () => { it('should return attachments with a valid name from getAttachmentProviders', async () => { const fs = mockStreamFileSystem(); - const session = new SessionFiles(fs, '.', 'sessionId'); + const session = new SessionFiles(fs, '.', { id: 'sessionId', timestamp: Date.now() }); const breadcrumbs: RawBreadcrumb[] = [ { diff --git a/packages/sdk-core/src/BacktraceCoreClient.ts b/packages/sdk-core/src/BacktraceCoreClient.ts index 82ed9dd2..2416b1a8 100644 --- a/packages/sdk-core/src/BacktraceCoreClient.ts +++ b/packages/sdk-core/src/BacktraceCoreClient.ts @@ -177,7 +177,10 @@ export abstract class BacktraceCoreClient< const sessionFiles = new SessionFiles( this.fileSystem, this.options.database.path, - this.sessionId, + { + id: this.sessionId, + timestamp: Date.now(), + }, this.options.database.maximumOldSessions ?? 1, ); this._modules.set(SessionFiles, sessionFiles); diff --git a/packages/sdk-core/src/modules/database/AttachmentBacktraceDatabaseFileRecord.ts b/packages/sdk-core/src/modules/database/AttachmentBacktraceDatabaseFileRecord.ts index 77bd78fa..a4f7cec7 100644 --- a/packages/sdk-core/src/modules/database/AttachmentBacktraceDatabaseFileRecord.ts +++ b/packages/sdk-core/src/modules/database/AttachmentBacktraceDatabaseFileRecord.ts @@ -1,6 +1,6 @@ import { BacktraceAttachment } from '../../model/attachment/index.js'; import { isFileAttachment } from '../attachments/isFileAttachment.js'; -import { FileSystem } from '../storage/index.js'; +import { FileSystem, SessionId } from '../storage/index.js'; import { BacktraceDatabaseFileRecord } from './BacktraceDatabaseFileRecord.js'; import { AttachmentBacktraceDatabaseRecord } from './model/BacktraceDatabaseRecord.js'; @@ -10,7 +10,7 @@ export class AttachmentBacktraceDatabaseFileRecord implements AttachmentBacktrac public readonly rxid: string; public readonly timestamp: number; public readonly attachment: BacktraceAttachment; - public readonly sessionId: string; + public readonly sessionId: SessionId | string; public locked: boolean; private constructor(record: AttachmentBacktraceDatabaseRecord) { diff --git a/packages/sdk-core/src/modules/database/BacktraceDatabase.ts b/packages/sdk-core/src/modules/database/BacktraceDatabase.ts index fad3ca81..2c7fb15a 100644 --- a/packages/sdk-core/src/modules/database/BacktraceDatabase.ts +++ b/packages/sdk-core/src/modules/database/BacktraceDatabase.ts @@ -8,7 +8,7 @@ import { BacktraceDatabaseConfiguration } from '../../model/configuration/Backtr import { BacktraceData } from '../../model/data/BacktraceData.js'; import { BacktraceReportSubmission } from '../../model/http/BacktraceReportSubmission.js'; import { BacktraceModule, BacktraceModuleBindData } from '../BacktraceModule.js'; -import { SessionFiles } from '../storage/index.js'; +import { SessionFiles, SessionId } from '../storage/index.js'; import { BacktraceDatabaseContext } from './BacktraceDatabaseContext.js'; import { BacktraceDatabaseEvents } from './BacktraceDatabaseEvents.js'; import { BacktraceDatabaseStorageProvider } from './BacktraceDatabaseStorageProvider.js'; @@ -135,8 +135,6 @@ export class BacktraceDatabase extends Events implement return undefined; } - const sessionId = backtraceData.attributes?.['application.session']; - const record: ReportBacktraceDatabaseRecord = { type: 'report', data: backtraceData, @@ -144,7 +142,7 @@ export class BacktraceDatabase extends Events implement id: IdGenerator.uuid(), locked: false, attachments: attachments, - sessionId: typeof sessionId === 'string' ? sessionId : undefined, + sessionId: this._sessionFiles?.sessionId, }; this.prepareDatabase([record]); @@ -171,7 +169,7 @@ export class BacktraceDatabase extends Events implement public addAttachment( rxid: string, attachment: BacktraceAttachment, - sessionId: string, + sessionId: SessionId, ): AttachmentBacktraceDatabaseRecord | undefined { if (!this._enabled) { return undefined; @@ -398,7 +396,7 @@ export class BacktraceDatabase extends Events implement } const sessionId = record.sessionId; - if (typeof sessionId !== 'string') { + if (!SessionFiles.isValidSessionId(sessionId)) { this._sessionFiles.lockPreviousSessions(record.id); return; } diff --git a/packages/sdk-core/src/modules/database/ReportBacktraceDatabaseFileRecord.ts b/packages/sdk-core/src/modules/database/ReportBacktraceDatabaseFileRecord.ts index 0a2c2c2d..02bc2e0b 100644 --- a/packages/sdk-core/src/modules/database/ReportBacktraceDatabaseFileRecord.ts +++ b/packages/sdk-core/src/modules/database/ReportBacktraceDatabaseFileRecord.ts @@ -1,7 +1,7 @@ import { BacktraceAttachment } from '../../model/attachment/index.js'; import { BacktraceData } from '../../model/data/index.js'; import { isFileAttachment } from '../attachments/isFileAttachment.js'; -import { FileSystem } from '../storage/index.js'; +import { FileSystem, SessionId } from '../storage/index.js'; import { BacktraceDatabaseFileRecord } from './BacktraceDatabaseFileRecord.js'; import { ReportBacktraceDatabaseRecord } from './model/BacktraceDatabaseRecord.js'; @@ -10,7 +10,7 @@ export class ReportBacktraceDatabaseFileRecord implements ReportBacktraceDatabas public readonly data: BacktraceData; public readonly id: string; public readonly timestamp: number; - public readonly sessionId?: string; + public readonly sessionId?: SessionId | string; public locked: boolean; private constructor( diff --git a/packages/sdk-core/src/modules/database/model/BacktraceDatabaseRecord.ts b/packages/sdk-core/src/modules/database/model/BacktraceDatabaseRecord.ts index f8999013..8048c9a4 100644 --- a/packages/sdk-core/src/modules/database/model/BacktraceDatabaseRecord.ts +++ b/packages/sdk-core/src/modules/database/model/BacktraceDatabaseRecord.ts @@ -1,12 +1,13 @@ import { BacktraceAttachment } from '../../../model/attachment/index.js'; import { BacktraceData } from '../../../model/data/BacktraceData.js'; +import { SessionId } from '../../storage/SessionFiles.js'; export interface ReportBacktraceDatabaseRecord { readonly type: 'report'; readonly data: BacktraceData; readonly id: string; readonly timestamp: number; - readonly sessionId?: string; + readonly sessionId?: string | SessionId; attachments: BacktraceAttachment[]; /** * Determines if the record is in use @@ -20,7 +21,7 @@ export interface AttachmentBacktraceDatabaseRecord { readonly rxid: string; readonly timestamp: number; readonly attachment: BacktraceAttachment; - readonly sessionId: string; + readonly sessionId: string | SessionId; /** * Determines if the record is in use */ diff --git a/packages/sdk-core/src/modules/storage/SessionFiles.ts b/packages/sdk-core/src/modules/storage/SessionFiles.ts index 279614b6..0ba33489 100644 --- a/packages/sdk-core/src/modules/storage/SessionFiles.ts +++ b/packages/sdk-core/src/modules/storage/SessionFiles.ts @@ -5,15 +5,19 @@ import { FileSystem } from './FileSystem.js'; interface FileSession { readonly file: string; - readonly sessionId: string; + readonly sessionId: SessionId; readonly escapedSessionId: string; - readonly timestamp: number; } type SessionEvents = { unlocked: []; }; +export interface SessionId { + readonly id: string; + readonly timestamp: number; +} + const SESSION_MARKER_PREFIX = 'bt-session'; const isDefined = (t: T | undefined): t is T => !!t; @@ -30,17 +34,16 @@ export class SessionFiles implements BacktraceModule { constructor( private readonly _fileSystem: FileSystem, private readonly _directory: string, - public readonly sessionId: string, + public readonly sessionId: SessionId, private readonly _maxPreviousLockedSessions = 1, - public readonly timestamp = Date.now(), private readonly _lockable = true, ) { - this._escapedSessionId = this.escapeFileName(sessionId); + this._escapedSessionId = this.escapeFileName(sessionId.id); this.marker = this.getFileName(SESSION_MARKER_PREFIX); } public initialize(): void { - this.createSessionMarker(); + return this.createSessionMarker(); } public getPreviousSession() { @@ -57,12 +60,14 @@ export class SessionFiles implements BacktraceModule { .filter((f) => f.startsWith(SESSION_MARKER_PREFIX)) .map((f) => this.getFileSession(f)) .filter(isDefined) - .sort((a, b) => b.timestamp - a.timestamp); + .sort((a, b) => b.sessionId.timestamp - a.sessionId.timestamp); - const currentSessionMarker = sessionMarkers.find((s) => s.sessionId === this.sessionId); + const currentSessionMarker = sessionMarkers.find((s) => this.sessionIdEquals(s.sessionId, this.sessionId)); const lastSessionMarker = currentSessionMarker - ? sessionMarkers.filter(({ timestamp }) => currentSessionMarker.timestamp > timestamp)[0] + ? sessionMarkers.filter( + ({ sessionId }) => currentSessionMarker.sessionId.timestamp > sessionId.timestamp, + )[0] : sessionMarkers[0]; if (!lastSessionMarker) { @@ -74,15 +79,14 @@ export class SessionFiles implements BacktraceModule { this._directory, lastSessionMarker.sessionId, this._maxPreviousLockedSessions - 1, - lastSessionMarker.timestamp, this._maxPreviousLockedSessions > 0, )); } - public getSessionWithId(sessionId: string) { + public getSessionWithId(sessionId: SessionId) { // eslint-disable-next-line @typescript-eslint/no-this-alias let session: SessionFiles | undefined = this; - while (session && session.sessionId !== sessionId) { + while (session && this.sessionIdEquals(session.sessionId, sessionId)) { session = session.getPreviousSession(); } @@ -124,7 +128,11 @@ export class SessionFiles implements BacktraceModule { public getFileName(prefix: string) { this.throwIfCleared(); - return this._directory + '/' + `${this.escapeFileName(prefix)}_${this._escapedSessionId}_${this.timestamp}`; + return ( + this._directory + + '/' + + `${this.escapeFileName(prefix)}_${this._escapedSessionId}_${this.sessionId.timestamp}` + ); } public getSessionFiles() { @@ -134,7 +142,7 @@ export class SessionFiles implements BacktraceModule { return files .map((file) => this.getFileSession(file)) .filter(isDefined) - .filter(({ sessionId }) => sessionId === this.sessionId) + .filter(({ sessionId }) => this.sessionIdEquals(sessionId, this.sessionId)) .map(({ file }) => this._directory + '/' + file); } @@ -184,7 +192,14 @@ export class SessionFiles implements BacktraceModule { return undefined; } - return { file, escapedSessionId, timestamp, sessionId: this.unescapeFileName(escapedSessionId) }; + return { + file, + escapedSessionId, + sessionId: { + timestamp, + id: this.unescapeFileName(escapedSessionId), + }, + }; } private readDirectoryFiles() { @@ -232,4 +247,19 @@ export class SessionFiles implements BacktraceModule { throw new Error('This session files are cleared.'); } } + + private sessionIdEquals(a: SessionId, b: SessionId) { + return a.id === b.id && a.timestamp === b.timestamp; + } + + public static isValidSessionId(value: unknown): value is SessionId { + return ( + typeof value === 'object' && + !!value && + 'id' in value && + 'timestamp' in value && + typeof value.id === 'string' && + typeof value.timestamp === 'number' + ); + } } diff --git a/packages/sdk-core/tests/database/databaseSetupTests.spec.ts b/packages/sdk-core/tests/database/databaseSetupTests.spec.ts index bfe8476d..4c7238da 100644 --- a/packages/sdk-core/tests/database/databaseSetupTests.spec.ts +++ b/packages/sdk-core/tests/database/databaseSetupTests.spec.ts @@ -28,7 +28,7 @@ function randomAttachmentRecord(): AttachmentBacktraceDatabaseRecord { timestamp: Date.now(), attachment: { name: 'x', get: () => undefined }, rxid: 'x', - sessionId: crypto.randomUUID(), + sessionId: { id: crypto.randomUUID(), timestamp: Date.now() }, }; } diff --git a/packages/sdk-core/tests/storage/SessionFiles.spec.ts b/packages/sdk-core/tests/storage/SessionFiles.spec.ts index dc26e4b5..a457f535 100644 --- a/packages/sdk-core/tests/storage/SessionFiles.spec.ts +++ b/packages/sdk-core/tests/storage/SessionFiles.spec.ts @@ -1,11 +1,18 @@ import assert from 'assert'; -import { SessionFiles } from '../../src/modules/storage/SessionFiles.js'; +import { SessionFiles, SessionId } from '../../src/modules/storage/SessionFiles.js'; import { mockFileSystem } from '../_mocks/fileSystem.js'; describe('SessionFiles', () => { + function sessionId(id: string, timestamp?: number): SessionId { + return { + id, + timestamp: timestamp ?? Date.now(), + }; + } + it('should create empty session marker on initialize', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); expect(fileSystem.readFileSync(session.marker)).toEqual(''); @@ -14,7 +21,7 @@ describe('SessionFiles', () => { describe('getPreviousSession', () => { it('should return undefined if no previous session marker exists', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const previous = session.getPreviousSession(); @@ -23,10 +30,10 @@ describe('SessionFiles', () => { it('should return previous session if previous session marker exists', () => { const fileSystem = mockFileSystem(); - const previousSession = new SessionFiles(fileSystem, '.', 'previousSessionId', undefined, 10); + const previousSession = new SessionFiles(fileSystem, '.', sessionId('previousSessionId', 10)); previousSession.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20)); session.initialize(); const previous = session.getPreviousSession(); @@ -35,10 +42,10 @@ describe('SessionFiles', () => { it('should return previous session if previous session contains underscores', () => { const fileSystem = mockFileSystem(); - const previousSession = new SessionFiles(fileSystem, '.', 'previous_session_id', undefined, 10); + const previousSession = new SessionFiles(fileSystem, '.', sessionId('previous_session_id', 10)); previousSession.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20)); session.initialize(); const previous = session.getPreviousSession(); @@ -47,14 +54,14 @@ describe('SessionFiles', () => { it('should return session older than current if multiple previous session markers exist', () => { const fileSystem = mockFileSystem(); - const oldPreviousSession = new SessionFiles(fileSystem, '.', 'oldPreviousSessionId', undefined, 5); - const previousSession = new SessionFiles(fileSystem, '.', 'previousSessionId', undefined, 10); - const nextSession = new SessionFiles(fileSystem, '.', 'nextSessionId', undefined, 25); + const oldPreviousSession = new SessionFiles(fileSystem, '.', sessionId('oldPreviousSessionId', 5)); + const previousSession = new SessionFiles(fileSystem, '.', sessionId('previousSessionId', 10)); + const nextSession = new SessionFiles(fileSystem, '.', sessionId('nextSessionId', 25)); oldPreviousSession.initialize(); previousSession.initialize(); nextSession.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20)); session.initialize(); const previous = session.getPreviousSession(); @@ -63,14 +70,14 @@ describe('SessionFiles', () => { it('should return previous session of each session', () => { const fileSystem = mockFileSystem(); - const session1 = new SessionFiles(fileSystem, '.', 'session1', undefined, 5); - const session2 = new SessionFiles(fileSystem, '.', 'session2', undefined, 10); - const session3 = new SessionFiles(fileSystem, '.', 'session3', undefined, 15); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1', 5)); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2', 10)); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3', 15)); session1.initialize(); session2.initialize(); session3.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20)); session.initialize(); const actualSession3 = session.getPreviousSession(); @@ -86,14 +93,14 @@ describe('SessionFiles', () => { it('should return non-lockable session when maxPreviousLockedSessions is 0', () => { const fileSystem = mockFileSystem(); - const session1 = new SessionFiles(fileSystem, '.', 'session1', undefined, 5); - const session2 = new SessionFiles(fileSystem, '.', 'session2', undefined, 10); - const session3 = new SessionFiles(fileSystem, '.', 'session3', undefined, 15); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1', 5)); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2', 10)); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3', 15)); session1.initialize(); session2.initialize(); session3.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', 0, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20), 0); session.initialize(); const previousSession = session.getPreviousSession(); @@ -104,14 +111,14 @@ describe('SessionFiles', () => { it('should return lockable session when maxPreviousLockedSessions is larger than 0', () => { const fileSystem = mockFileSystem(); - const session1 = new SessionFiles(fileSystem, '.', 'session1', undefined, 5); - const session2 = new SessionFiles(fileSystem, '.', 'session2', undefined, 10); - const session3 = new SessionFiles(fileSystem, '.', 'session3', undefined, 15); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1', 5)); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2', 10)); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3', 15)); session1.initialize(); session2.initialize(); session3.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', 1, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20), 1); session.initialize(); const previousSession = session.getPreviousSession(); @@ -122,14 +129,14 @@ describe('SessionFiles', () => { it('should return non-lockable session from previous session when maxPreviousLockedSessions is 1', () => { const fileSystem = mockFileSystem(); - const session1 = new SessionFiles(fileSystem, '.', 'session1', undefined, 5); - const session2 = new SessionFiles(fileSystem, '.', 'session2', undefined, 10); - const session3 = new SessionFiles(fileSystem, '.', 'session3', undefined, 15); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1', 5)); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2', 10)); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3', 15)); session1.initialize(); session2.initialize(); session3.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', 0, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20), 0); session.initialize(); const previousSession = session.getPreviousSession()?.getPreviousSession(); @@ -142,14 +149,14 @@ describe('SessionFiles', () => { describe('getPreviousSessions', () => { it('should return all previous sessions', () => { const fileSystem = mockFileSystem(); - const session1 = new SessionFiles(fileSystem, '.', 'session1', undefined, 5); - const session2 = new SessionFiles(fileSystem, '.', 'session2', undefined, 10); - const session3 = new SessionFiles(fileSystem, '.', 'session3', undefined, 15); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1', 5)); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2', 10)); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3', 15)); session1.initialize(); session2.initialize(); session3.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20)); session.initialize(); const previousSessions = session.getPreviousSessions(); @@ -163,14 +170,14 @@ describe('SessionFiles', () => { it('should return previous sessions limited by count', () => { const fileSystem = mockFileSystem(); - const session1 = new SessionFiles(fileSystem, '.', 'session1', undefined, 5); - const session2 = new SessionFiles(fileSystem, '.', 'session2', undefined, 10); - const session3 = new SessionFiles(fileSystem, '.', 'session3', undefined, 15); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1', 5)); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2', 10)); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3', 15)); session1.initialize(); session2.initialize(); session3.initialize(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, 20); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId', 20)); session.initialize(); const previousSessions = session.getPreviousSessions(2); @@ -182,7 +189,7 @@ describe('SessionFiles', () => { describe('getFileName', () => { it('should return file name with escaped session ID', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); const filename = session.getFileName('file_name'); expect(filename).toContain('file__name'); @@ -190,7 +197,7 @@ describe('SessionFiles', () => { it('should return file name with escaped file name', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'session_id'); + const session = new SessionFiles(fileSystem, '.', sessionId('session_id')); const filename = session.getFileName('file_name'); expect(filename).toContain('session__id'); @@ -199,7 +206,7 @@ describe('SessionFiles', () => { it('should return file name with session timestamp', () => { const fileSystem = mockFileSystem(); const timestamp = 123812412; - const session = new SessionFiles(fileSystem, '.', 'session_id', undefined, timestamp); + const session = new SessionFiles(fileSystem, '.', sessionId('session_id', timestamp)); const filename = session.getFileName('file_name'); expect(filename).toContain(timestamp.toString()); @@ -207,7 +214,7 @@ describe('SessionFiles', () => { it('should throw after clearing', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'session_id'); + const session = new SessionFiles(fileSystem, '.', sessionId('session_id')); session.initialize(); session.clearSession(); @@ -220,7 +227,7 @@ describe('SessionFiles', () => { it('should return files matching session', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const files = [session.getFileName('file1'), session.getFileName('file2'), session.getFileName('file3')]; @@ -235,12 +242,12 @@ describe('SessionFiles', () => { it('should not return files not matching session', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); - const session1 = new SessionFiles(fileSystem, '.', 'session1'); - const session2 = new SessionFiles(fileSystem, '.', 'session2'); - const session3 = new SessionFiles(fileSystem, '.', 'session3'); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1')); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2')); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3')); const files = [session1.getFileName('file1'), session2.getFileName('file2'), session3.getFileName('file3')]; for (const file of files) { @@ -253,7 +260,7 @@ describe('SessionFiles', () => { it('should throw after clearing', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'session_id'); + const session = new SessionFiles(fileSystem, '.', sessionId('session_id')); session.initialize(); session.clearSession(); @@ -265,7 +272,7 @@ describe('SessionFiles', () => { describe('clearSession', () => { it('should remove all files matching session', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const files = [session.getFileName('file1'), session.getFileName('file2'), session.getFileName('file3')]; @@ -282,12 +289,12 @@ describe('SessionFiles', () => { it('should not remove files not matching session', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); - const session1 = new SessionFiles(fileSystem, '.', 'session1'); - const session2 = new SessionFiles(fileSystem, '.', 'session2'); - const session3 = new SessionFiles(fileSystem, '.', 'session3'); + const session1 = new SessionFiles(fileSystem, '.', sessionId('session1')); + const session2 = new SessionFiles(fileSystem, '.', sessionId('session2')); + const session3 = new SessionFiles(fileSystem, '.', sessionId('session3')); const files = [session1.getFileName('file1'), session2.getFileName('file2'), session3.getFileName('file3')]; for (const file of files) { @@ -303,7 +310,7 @@ describe('SessionFiles', () => { it('should remove session marker', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); session.clearSession(); @@ -316,7 +323,7 @@ describe('SessionFiles', () => { describe('lock', () => { it('should return non-empty lock id when lock id is not provided', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const lockId = session.lock(); @@ -326,7 +333,7 @@ describe('SessionFiles', () => { it('should return provided lock id when lock id is provided', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const lockId = session.lock('lockId'); @@ -336,7 +343,7 @@ describe('SessionFiles', () => { it('should return undefined after cleared', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); session.clearSession(); @@ -347,7 +354,7 @@ describe('SessionFiles', () => { it('should return undefined when not lockable', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId', undefined, undefined, false); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId'), undefined, false); session.initialize(); session.clearSession(); @@ -360,7 +367,7 @@ describe('SessionFiles', () => { describe('clearSession', () => { it('should not clear files when session is locked', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const expected = { ...fileSystem.files }; @@ -374,7 +381,7 @@ describe('SessionFiles', () => { it('should clear files after unlocking when clearSession is called before', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const expected = { ...fileSystem.files }; @@ -390,7 +397,7 @@ describe('SessionFiles', () => { it('should not clear files after unlocking when clearSession is not called before', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const expected = { ...fileSystem.files }; @@ -404,7 +411,7 @@ describe('SessionFiles', () => { it('should not clear files after unlocking when locked with other locks', () => { const fileSystem = mockFileSystem(); - const session = new SessionFiles(fileSystem, '.', 'sessionId'); + const session = new SessionFiles(fileSystem, '.', sessionId('sessionId')); session.initialize(); const expected = { ...fileSystem.files };