diff --git a/packages/core/src/sdk/AccountInfoSingleton/AccountInfoSingleton.ts b/packages/core/src/sdk/AccountInfoSingleton/AccountInfoSingleton.ts index 439c1493a..8c4e983a9 100644 --- a/packages/core/src/sdk/AccountInfoSingleton/AccountInfoSingleton.ts +++ b/packages/core/src/sdk/AccountInfoSingleton/AccountInfoSingleton.ts @@ -4,7 +4,7 @@ * Copyright 2016-Present Datadog, Inc. */ -import { setCachedAccountId } from '../../rum/helper'; +import { clearCachedAccountId, setCachedAccountId } from '../../rum/helper'; import type { AccountInfo } from './types'; @@ -33,6 +33,7 @@ class AccountInfoProvider { clearAccountInfo = () => { this.accountInfo = undefined; + clearCachedAccountId(); }; } diff --git a/packages/core/src/sdk/AccountInfoSingleton/__tests__/AccountInfoSingleton.test.ts b/packages/core/src/sdk/AccountInfoSingleton/__tests__/AccountInfoSingleton.test.ts index 9af387619..1e5f91751 100644 --- a/packages/core/src/sdk/AccountInfoSingleton/__tests__/AccountInfoSingleton.test.ts +++ b/packages/core/src/sdk/AccountInfoSingleton/__tests__/AccountInfoSingleton.test.ts @@ -4,11 +4,49 @@ * Copyright 2016-Present Datadog, Inc. */ +import { + clearCachedAccountId, + clearCachedSessionId, + clearCachedUserId, + getCachedAccountId +} from '../../../rum/helper'; +import { firstPartyHostsRegexMapBuilder } from '../../../rum/instrumentation/resourceTracking/distributedTracing/firstPartyHosts'; +import { DATADOG_BAGGAGE_HEADER } from '../../../rum/instrumentation/resourceTracking/headers'; +import { createRequestContext } from '../../../rum/instrumentation/resourceTracking/requestProxy/common/RequestContext'; +import { getInstrumentationHeaders } from '../../../rum/instrumentation/resourceTracking/requestProxy/common/requestHeaders'; +import { PropagatorType } from '../../../rum/types'; import { AccountInfoSingleton } from '../AccountInfoSingleton'; +const firstPartyRequestOptions = { + tracingSamplingRate: 100, + firstPartyHostsRegexMap: firstPartyHostsRegexMapBuilder([ + { + match: 'api.example.com', + propagatorTypes: [ + PropagatorType.DATADOG, + PropagatorType.TRACECONTEXT + ] + } + ]) +}; + +const getBaggageHeader = (): string | undefined => { + const context = createRequestContext({ + method: 'GET', + url: 'https://api.example.com/v1/resource', + options: firstPartyRequestOptions + }); + return getInstrumentationHeaders(context).find( + header => header.header === DATADOG_BAGGAGE_HEADER + )?.value; +}; + describe('AccountInfoSingleton', () => { beforeEach(() => { AccountInfoSingleton.reset(); + clearCachedSessionId(); + clearCachedUserId(); + clearCachedAccountId(); }); it('returns undefined by default', () => { @@ -87,4 +125,25 @@ describe('AccountInfoSingleton', () => { expect(a).toBe(b); }); + + it('clears the cached account id used by RequestContext baggage after clearAccountInfo', () => { + const accountId = 'previous-account'; + AccountInfoSingleton.getInstance().setAccountInfo({ + id: accountId, + extraInfo: {} + }); + + expect(getCachedAccountId()).toBe(accountId); + expect(getBaggageHeader()).toBe(`account.id=${accountId}`); + + AccountInfoSingleton.getInstance().clearAccountInfo(); + + expect( + AccountInfoSingleton.getInstance().getAccountInfo() + ).toBeUndefined(); + expect(getCachedAccountId()).toBeUndefined(); + expect(getBaggageHeader() ?? '').not.toContain( + `account.id=${accountId}` + ); + }); }); diff --git a/packages/core/src/sdk/UserInfoSingleton/UserInfoSingleton.ts b/packages/core/src/sdk/UserInfoSingleton/UserInfoSingleton.ts index a33e494e9..cde32c2a5 100644 --- a/packages/core/src/sdk/UserInfoSingleton/UserInfoSingleton.ts +++ b/packages/core/src/sdk/UserInfoSingleton/UserInfoSingleton.ts @@ -4,7 +4,7 @@ * Copyright 2016-Present Datadog, Inc. */ -import { setCachedUserId } from '../../rum/helper'; +import { clearCachedUserId, setCachedUserId } from '../../rum/helper'; import type { UserInfo } from './types'; @@ -35,6 +35,7 @@ class UserInfoProvider { clearUserInfo = () => { this.userInfo = undefined; + clearCachedUserId(); }; } diff --git a/packages/core/src/sdk/UserInfoSingleton/__tests__/UserInfoSingleton.test.ts b/packages/core/src/sdk/UserInfoSingleton/__tests__/UserInfoSingleton.test.ts index f8e7276d6..719300a07 100644 --- a/packages/core/src/sdk/UserInfoSingleton/__tests__/UserInfoSingleton.test.ts +++ b/packages/core/src/sdk/UserInfoSingleton/__tests__/UserInfoSingleton.test.ts @@ -4,11 +4,49 @@ * Copyright 2016-Present Datadog, Inc. */ +import { + clearCachedAccountId, + clearCachedSessionId, + clearCachedUserId, + getCachedUserId +} from '../../../rum/helper'; +import { firstPartyHostsRegexMapBuilder } from '../../../rum/instrumentation/resourceTracking/distributedTracing/firstPartyHosts'; +import { DATADOG_BAGGAGE_HEADER } from '../../../rum/instrumentation/resourceTracking/headers'; +import { createRequestContext } from '../../../rum/instrumentation/resourceTracking/requestProxy/common/RequestContext'; +import { getInstrumentationHeaders } from '../../../rum/instrumentation/resourceTracking/requestProxy/common/requestHeaders'; +import { PropagatorType } from '../../../rum/types'; import { UserInfoSingleton } from '../UserInfoSingleton'; +const firstPartyRequestOptions = { + tracingSamplingRate: 100, + firstPartyHostsRegexMap: firstPartyHostsRegexMapBuilder([ + { + match: 'api.example.com', + propagatorTypes: [ + PropagatorType.DATADOG, + PropagatorType.TRACECONTEXT + ] + } + ]) +}; + +const getBaggageHeader = (): string | undefined => { + const context = createRequestContext({ + method: 'GET', + url: 'https://api.example.com/v1/resource', + options: firstPartyRequestOptions + }); + return getInstrumentationHeaders(context).find( + header => header.header === DATADOG_BAGGAGE_HEADER + )?.value; +}; + describe('UserInfoSingleton', () => { beforeEach(() => { UserInfoSingleton.reset(); + clearCachedSessionId(); + clearCachedUserId(); + clearCachedAccountId(); }); it('returns undefined by default', () => { @@ -63,4 +101,21 @@ describe('UserInfoSingleton', () => { expect(a).toBe(b); }); + + it('clears the cached user id used by RequestContext baggage after clearUserInfo', () => { + const userId = 'previous-user'; + UserInfoSingleton.getInstance().setUserInfo({ + id: userId, + extraInfo: {} + }); + + expect(getCachedUserId()).toBe(userId); + expect(getBaggageHeader()).toBe(`user.id=${userId}`); + + UserInfoSingleton.getInstance().clearUserInfo(); + + expect(UserInfoSingleton.getInstance().getUserInfo()).toBeUndefined(); + expect(getCachedUserId()).toBeUndefined(); + expect(getBaggageHeader() ?? '').not.toContain(`user.id=${userId}`); + }); });