Skip to content

Commit

Permalink
⚗️✨ [RUM-2445] implement Tracking Consent management (#2589)
Browse files Browse the repository at this point in the history
* ✨ [RUM-2445] introduce init param

* ✨ [RUM-2445] wait for consent before starting SDKs

* ✨ [RUM-2445] implement setTrackingConsent public API

* ♻️✅ [RUM-2445] modify session manager specs

Define "start(Rum|Logs)SessionManagerWithDefault" to avoid having to
pass new parameters everywhere.

* ✨ [RUM-2445] expire and renew session based on tracking consent state

* ✅ [RUM-2445] add e2e tests

* ✅👌 add an e2e test

* 👌 add jsdoc (also the logs public API I forgot)

* 👌 rename tracking consent state methods

* 👌 re-use TrackingConsentState instance

* ✅👌 add test on unsubscribe

* 👌✅ add some e2e tests for logs

* 📝👌 adjust comment
  • Loading branch information
BenoitZugmeyer authored Feb 12, 2024
1 parent f6f76a1 commit ed48184
Show file tree
Hide file tree
Showing 23 changed files with 784 additions and 161 deletions.
35 changes: 28 additions & 7 deletions packages/core/src/domain/configuration/configuration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ import {
isExperimentalFeatureEnabled,
resetExperimentalFeatures,
} from '../../tools/experimentalFeatures'
import { TrackingConsent } from '../trackingConsent'
import type { InitConfiguration } from './configuration'
import { validateAndBuildConfiguration } from './configuration'

describe('validateAndBuildConfiguration', () => {
const clientToken = 'some_client_token'

let displaySpy: jasmine.Spy<typeof display.error>

beforeEach(() => {
displaySpy = spyOn(display, 'error')
})

afterEach(() => {
resetExperimentalFeatures()
})
Expand Down Expand Up @@ -44,12 +51,6 @@ describe('validateAndBuildConfiguration', () => {
})

describe('validate init configuration', () => {
let displaySpy: jasmine.Spy<typeof display.error>

beforeEach(() => {
displaySpy = spyOn(display, 'error')
})

it('requires the InitConfiguration to be defined', () => {
expect(validateAndBuildConfiguration(undefined as unknown as InitConfiguration)).toBeUndefined()
expect(displaySpy).toHaveBeenCalledOnceWith('Client Token is not configured, we will not send any data.')
Expand Down Expand Up @@ -160,7 +161,6 @@ describe('validateAndBuildConfiguration', () => {
throw myError
}
const configuration = validateAndBuildConfiguration({ clientToken, beforeSend })!
const displaySpy = spyOn(display, 'error')
expect(configuration.beforeSend!(null, {})).toBeUndefined()
expect(displaySpy).toHaveBeenCalledWith('beforeSend threw an error:', myError)
})
Expand All @@ -186,4 +186,25 @@ describe('validateAndBuildConfiguration', () => {
).toBeTrue()
})
})

describe('trackingConsent', () => {
it('defaults to "granted"', () => {
expect(validateAndBuildConfiguration({ clientToken: 'yes' })!.trackingConsent).toBe(TrackingConsent.GRANTED)
})

it('is set to provided value', () => {
expect(
validateAndBuildConfiguration({ clientToken: 'yes', trackingConsent: TrackingConsent.NOT_GRANTED })!
.trackingConsent
).toBe(TrackingConsent.NOT_GRANTED)
expect(
validateAndBuildConfiguration({ clientToken: 'yes', trackingConsent: TrackingConsent.GRANTED })!.trackingConsent
).toBe(TrackingConsent.GRANTED)
})

it('rejects invalid values', () => {
expect(validateAndBuildConfiguration({ clientToken: 'yes', trackingConsent: 'foo' as any })).toBeUndefined()
expect(displaySpy).toHaveBeenCalledOnceWith('Tracking Consent should be either "granted" or "not-granted"')
})
})
})
12 changes: 12 additions & 0 deletions packages/core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { objectHasValue } from '../../tools/utils/objectUtils'
import { assign } from '../../tools/utils/polyfills'
import { selectSessionStoreStrategyType } from '../session/sessionStore'
import type { SessionStoreStrategyType } from '../session/storeStrategies/sessionStoreStrategy'
import { TrackingConsent } from '../trackingConsent'
import type { TransportConfiguration } from './transportConfiguration'
import { computeTransportConfiguration } from './transportConfiguration'

Expand All @@ -30,6 +31,7 @@ export interface InitConfiguration {
allowFallbackToLocalStorage?: boolean | undefined
allowUntrustedEvents?: boolean | undefined
storeContextsAcrossPages?: boolean | undefined
trackingConsent?: TrackingConsent | undefined

// transport options
proxy?: string | ProxyFn | undefined
Expand Down Expand Up @@ -84,6 +86,7 @@ export interface Configuration extends TransportConfiguration {
service: string | undefined
silentMultipleInit: boolean
allowUntrustedEvents: boolean
trackingConsent: TrackingConsent

// Event limits
eventRateLimiterThreshold: number // Limit the maximum number of actions, errors and logs per minutes
Expand Down Expand Up @@ -120,6 +123,14 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
return
}

if (
initConfiguration.trackingConsent !== undefined &&
!objectHasValue(TrackingConsent, initConfiguration.trackingConsent)
) {
display.error('Tracking Consent should be either "granted" or "not-granted"')
return
}

// Set the experimental feature flags as early as possible, so we can use them in most places
if (Array.isArray(initConfiguration.enableExperimentalFeatures)) {
addExperimentalFeatures(
Expand All @@ -140,6 +151,7 @@ export function validateAndBuildConfiguration(initConfiguration: InitConfigurati
service: initConfiguration.service,
silentMultipleInit: !!initConfiguration.silentMultipleInit,
allowUntrustedEvents: !!initConfiguration.allowUntrustedEvents,
trackingConsent: initConfiguration.trackingConsent ?? TrackingConsent.GRANTED,

/**
* beacon payload max queue size implementation is 64kb
Expand Down
Loading

0 comments on commit ed48184

Please sign in to comment.