88/* eslint-disable camelcase */
99
1010import { writeFile , mkdir , readFile } from 'node:fs/promises' ;
11- import { existsSync } from 'node:fs' ;
12- import { sep , dirname } from 'node:path' ;
11+ import { existsSync , rmSync } from 'node:fs' ;
12+ import { sep , dirname , resolve } from 'node:path' ;
1313import { MockTestOrgData , instantiateContext , stubContext , restoreContext } from '@salesforce/core/testSetup' ;
1414import { EnvVars , envVars , Messages , Org } from '@salesforce/core' ;
1515import { expect , config } from 'chai' ;
@@ -74,7 +74,6 @@ type SetContentsInput = {
7474} ;
7575describe ( 'remoteSourceTrackingService' , ( ) => {
7676 const username = 'foo@bar.com' ;
77- let orgId : string ;
7877 const $$ = instantiateContext ( ) ;
7978 let remoteSourceTrackingService : RemoteSourceTrackingService ;
8079
@@ -97,15 +96,14 @@ describe('remoteSourceTrackingService', () => {
9796 sourceMembers : Object . fromEntries ( remoteSourceTrackingService . sourceMembers ) ,
9897 } ) ;
9998
100- afterEach ( async ( ) => {
101- await RemoteSourceTrackingService . delete ( orgId ) ;
99+ afterEach ( ( ) => {
100+ RemoteSourceTrackingService [ 'instanceMap' ] . clear ( ) ;
102101 restoreContext ( $$ ) ;
103102 } ) ;
104103
105104 beforeEach ( async ( ) => {
106105 stubContext ( $$ ) ;
107106 const orgData = new MockTestOrgData ( ) ;
108- orgId = orgData . orgId ;
109107 orgData . username = username ;
110108 orgData . tracksSource = true ;
111109 await $$ . stubAuths ( orgData ) ;
@@ -115,57 +113,57 @@ describe('remoteSourceTrackingService', () => {
115113 org,
116114 projectPath : await $$ . localPathRetriever ( $$ . id ) ,
117115 } ) ;
116+ } ) ;
118117
119- describe ( 'remoteChangeElementToChangeResult()' , ( ) => {
120- const memberIdOrName = '00eO4000003cP5J' ;
121- it ( 'should return correct ChangeResult for EmailTemplateFolder' , ( ) => {
122- const rce : RemoteChangeElement = {
123- name : 'level1/level2/level3' ,
124- type : 'EmailTemplateFolder' ,
125- deleted : false ,
126- modified : true ,
127- changedBy : 'Shelby McLaughlin' ,
128- revisionCounter : 1 ,
129- memberIdOrName,
130- lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
131- } ;
132- const changeResult = remoteChangeElementToChangeResult ( rce ) ;
133- expect ( changeResult ) . to . deep . equal ( {
134- origin : 'remote' ,
135- name : 'level1/level2/level3' ,
136- type : 'EmailFolder' ,
137- deleted : false ,
138- modified : true ,
139- changedBy : 'Shelby McLaughlin' ,
140- revisionCounter : 1 ,
141- memberIdOrName,
142- lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
143- } ) ;
118+ describe ( 'remoteChangeElementToChangeResult()' , ( ) => {
119+ const memberIdOrName = '00eO4000003cP5J' ;
120+ it ( 'should return correct ChangeResult for EmailTemplateFolder' , ( ) => {
121+ const rce : RemoteChangeElement = {
122+ name : 'level1/level2/level3' ,
123+ type : 'EmailTemplateFolder' ,
124+ deleted : false ,
125+ modified : true ,
126+ changedBy : 'Shelby McLaughlin' ,
127+ revisionCounter : 1 ,
128+ memberIdOrName,
129+ lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
130+ } ;
131+ const changeResult = remoteChangeElementToChangeResult ( rce ) ;
132+ expect ( changeResult ) . to . deep . equal ( {
133+ origin : 'remote' ,
134+ name : 'level1/level2/level3' ,
135+ type : 'EmailFolder' ,
136+ deleted : false ,
137+ modified : true ,
138+ changedBy : 'Shelby McLaughlin' ,
139+ revisionCounter : 1 ,
140+ memberIdOrName,
141+ lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
144142 } ) ;
143+ } ) ;
145144
146- it ( 'should return correct ChangeResult for LightningComponentResource' , ( ) => {
147- const rce : RemoteChangeElement = {
148- name : 'fooLWC/bar' ,
149- type : 'LightningComponentResource' ,
150- deleted : false ,
151- modified : true ,
152- changedBy : 'Shelby McLaughlin' ,
153- revisionCounter : 1 ,
154- memberIdOrName,
155- lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
156- } ;
157- const changeResult = remoteChangeElementToChangeResult ( rce ) ;
158- expect ( changeResult ) . to . deep . equal ( {
159- origin : 'remote' ,
160- name : 'fooLWC' ,
161- type : 'LightningComponentBundle' ,
162- deleted : false ,
163- modified : true ,
164- changedBy : 'Shelby McLaughlin' ,
165- revisionCounter : 1 ,
166- memberIdOrName,
167- lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
168- } ) ;
145+ it ( 'should return correct ChangeResult for LightningComponentResource' , ( ) => {
146+ const rce : RemoteChangeElement = {
147+ name : 'fooLWC/bar' ,
148+ type : 'LightningComponentResource' ,
149+ deleted : false ,
150+ modified : true ,
151+ changedBy : 'Shelby McLaughlin' ,
152+ revisionCounter : 1 ,
153+ memberIdOrName,
154+ lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
155+ } ;
156+ const changeResult = remoteChangeElementToChangeResult ( rce ) ;
157+ expect ( changeResult ) . to . deep . equal ( {
158+ origin : 'remote' ,
159+ name : 'fooLWC' ,
160+ type : 'LightningComponentBundle' ,
161+ deleted : false ,
162+ modified : true ,
163+ changedBy : 'Shelby McLaughlin' ,
164+ revisionCounter : 1 ,
165+ memberIdOrName,
166+ lastModifiedDate : defaultSourceMemberValues . LastModifiedDate ,
169167 } ) ;
170168 } ) ;
171169 } ) ;
@@ -178,6 +176,50 @@ describe('remoteSourceTrackingService', () => {
178176 } ) ;
179177 } ) ;
180178
179+ describe ( 'getInstance' , ( ) => {
180+ const org2Dir = resolve ( 'temp2' ) ;
181+ const org3Dir = resolve ( 'temp3' ) ;
182+
183+ it ( 'should purge old instances when they exceed MAX_INSTANCE_CACHE_TTL' , async ( ) => {
184+ // Create second instance
185+ const org2 = await Org . create ( { aliasOrUsername : 'org2@test.com' } ) ;
186+ $$ . SANDBOX . stub ( org2 , 'getOrgId' ) . returns ( '00D999999999999999' ) ;
187+ await RemoteSourceTrackingService . getInstance ( {
188+ org : org2 ,
189+ projectPath : org2Dir ,
190+ } ) ;
191+
192+ // Verify both instances exist
193+ expect ( RemoteSourceTrackingService [ 'instanceMap' ] . size ) . to . equal ( 2 ) ;
194+
195+ // Get a date that is over 1 hour from now
196+ const MAX_INSTANCE_CACHE_TTL = 1000 * 60 * 60 * 1 ; // 1 hour
197+ const futureDateNow = Date . now ( ) + MAX_INSTANCE_CACHE_TTL + 1000 ;
198+
199+ // Stub Date.now to simulate time passing
200+ const dateNowStub = $$ . SANDBOX . stub ( Date , 'now' ) . returns ( futureDateNow ) ;
201+
202+ // Create a new instance which should trigger purge
203+ const org3 = await Org . create ( { aliasOrUsername : 'org3@test.com' } ) ;
204+ $$ . SANDBOX . stub ( org3 , 'getOrgId' ) . returns ( '00D777777777777777' ) ;
205+ await RemoteSourceTrackingService . getInstance ( {
206+ org : org3 ,
207+ projectPath : org3Dir ,
208+ } ) ;
209+
210+ // Verify old instances were purged
211+ expect ( RemoteSourceTrackingService [ 'instanceMap' ] . size ) . to . equal ( 1 ) ;
212+ expect ( RemoteSourceTrackingService [ 'instanceMap' ] . get ( '00D777777777777777' ) ) . to . be . an ( 'object' ) ;
213+ expect ( dateNowStub . called ) . to . equal ( true ) ;
214+ } ) ;
215+
216+ afterEach ( ( ) => {
217+ // clean up the tracking files created by the tests
218+ rmSync ( org2Dir , { recursive : true } ) ;
219+ rmSync ( org3Dir , { recursive : true } ) ;
220+ } ) ;
221+ } ) ;
222+
181223 describe ( 'init' , ( ) => {
182224 it ( 'should set initial state of contents' , async ( ) => {
183225 const queryMembersFromSpy = $$ . SANDBOX . spy ( orgQueryMocks , 'querySourceMembersFrom' ) ;
0 commit comments