diff --git a/packages/client-sdk-nodejs/test/integration/shared/cache/replica-reads.test.ts b/packages/client-sdk-nodejs/test/integration/shared/cache/replica-reads.test.ts new file mode 100644 index 000000000..b6ba0806a --- /dev/null +++ b/packages/client-sdk-nodejs/test/integration/shared/cache/replica-reads.test.ts @@ -0,0 +1,10 @@ +import {runReplicaReadTests} from '@gomomento/common-integration-tests'; +import {SetupIntegrationTest} from '../../integration-setup'; + +const {cacheClientWithBalancedReadConcern, integrationTestCacheName} = + SetupIntegrationTest(); + +runReplicaReadTests( + cacheClientWithBalancedReadConcern, + integrationTestCacheName +); diff --git a/packages/client-sdk-web/test/integration/shared/cache/replica-reads.test.ts b/packages/client-sdk-web/test/integration/shared/cache/replica-reads.test.ts new file mode 100644 index 000000000..b6ba0806a --- /dev/null +++ b/packages/client-sdk-web/test/integration/shared/cache/replica-reads.test.ts @@ -0,0 +1,10 @@ +import {runReplicaReadTests} from '@gomomento/common-integration-tests'; +import {SetupIntegrationTest} from '../../integration-setup'; + +const {cacheClientWithBalancedReadConcern, integrationTestCacheName} = + SetupIntegrationTest(); + +runReplicaReadTests( + cacheClientWithBalancedReadConcern, + integrationTestCacheName +); diff --git a/packages/common-integration-tests/src/cache/replica-reads.ts b/packages/common-integration-tests/src/cache/replica-reads.ts new file mode 100644 index 000000000..4b873ba2f --- /dev/null +++ b/packages/common-integration-tests/src/cache/replica-reads.ts @@ -0,0 +1,61 @@ +import {v4} from 'uuid'; +import {CacheGet, CacheSet} from '@gomomento/sdk-core'; +import {expectWithMessage} from '../common-int-test-utils'; +import {ICacheClient} from '@gomomento/sdk-core/dist/src/internal/clients/cache'; + +export function runReplicaReadTests( + cacheClientWithBalancedReadConcern: ICacheClient, + integrationTestCacheName: string +) { + describe('Replica Read Tests', () => { + it('should read the latest value after replication delay using balanced read concern', async () => { + const client = cacheClientWithBalancedReadConcern; + const numTrials = 10; + const delayBetweenTrials = 100; + const replicationDelayMs = 1000; + const trials = []; + + const trialFn = async (trialNumber: number) => { + // Start this trial at it's own time plus a random delay + const startDelay = + trialNumber * delayBetweenTrials + (Math.random() - 0.5) * 10; + await new Promise(resolve => setTimeout(resolve, startDelay)); + + const cacheKey = v4(); + const cacheValue = v4(); + + // Perform a set operation + const setResponse = await client.set( + integrationTestCacheName, + cacheKey, + cacheValue + ); + expectWithMessage(() => { + expect(setResponse).toBeInstanceOf(CacheSet.Success); + }, `expected SUCCESS but got ${setResponse.toString()}`); + + // Wait for replication to complete + await new Promise(resolve => setTimeout(resolve, replicationDelayMs)); + + // Verify that the value can be read + const getResponse = await client.get( + integrationTestCacheName, + cacheKey + ); + expectWithMessage(() => { + expect(getResponse).toBeInstanceOf(CacheGet.Hit); + }, `expected HIT but got ${getResponse.toString()}`); + + expectWithMessage(() => { + expect(getResponse.value()).toEqual(cacheValue); + }, `expected ${cacheValue} but got ${getResponse.value() ?? 'undefined'}`); + }; + + for (let i = 0; i < numTrials; i++) { + trials.push(trialFn(i)); + } + + await Promise.all(trials); + }); + }); +} diff --git a/packages/common-integration-tests/src/index.ts b/packages/common-integration-tests/src/index.ts index f6d11a2db..8bad98df4 100644 --- a/packages/common-integration-tests/src/index.ts +++ b/packages/common-integration-tests/src/index.ts @@ -14,4 +14,5 @@ export * from './cache/update-ttl'; export * from './leaderboard/leaderboard-client'; export * from './webhooks/webhooks'; export * from './cache/batch-get-set'; +export * from './cache/replica-reads'; export * from './storage/storage';