From d27ef2df4d1e1f3113d0469710287c90d3e295dd Mon Sep 17 00:00:00 2001
From: Peter Perlepes
Date: Thu, 29 Jun 2023 13:04:25 +0300
Subject: [PATCH] Add tracker.getQueueName method (close #1215)
---
...15-expose-queue-name_2023-06-29-15-53.json | 10 ++++
...15-expose-queue-name_2023-06-29-15-54.json | 10 ++++
.../browser-tracker-core/src/tracker/index.ts | 2 +
.../src/tracker/out_queue.ts | 26 +++++++---
.../browser-tracker-core/src/tracker/types.ts | 5 ++
.../test/out_queue.test.ts | 48 +++++++++++++++++++
.../docs/browser-tracker.api.md | 1 +
.../browser-tracker/test/helpers/index.ts | 6 +++
trackers/browser-tracker/test/tracker.test.ts | 22 +++++++++
9 files changed, 123 insertions(+), 7 deletions(-)
create mode 100644 common/changes/@snowplow/browser-tracker-core/feature-1215-expose-queue-name_2023-06-29-15-53.json
create mode 100644 common/changes/@snowplow/browser-tracker/feature-1215-expose-queue-name_2023-06-29-15-54.json
create mode 100644 trackers/browser-tracker/test/helpers/index.ts
diff --git a/common/changes/@snowplow/browser-tracker-core/feature-1215-expose-queue-name_2023-06-29-15-53.json b/common/changes/@snowplow/browser-tracker-core/feature-1215-expose-queue-name_2023-06-29-15-53.json
new file mode 100644
index 000000000..e4a7a4161
--- /dev/null
+++ b/common/changes/@snowplow/browser-tracker-core/feature-1215-expose-queue-name_2023-06-29-15-53.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@snowplow/browser-tracker-core",
+ "comment": "Expose getQueueName method",
+ "type": "none"
+ }
+ ],
+ "packageName": "@snowplow/browser-tracker-core"
+}
\ No newline at end of file
diff --git a/common/changes/@snowplow/browser-tracker/feature-1215-expose-queue-name_2023-06-29-15-54.json b/common/changes/@snowplow/browser-tracker/feature-1215-expose-queue-name_2023-06-29-15-54.json
new file mode 100644
index 000000000..f85d4a1eb
--- /dev/null
+++ b/common/changes/@snowplow/browser-tracker/feature-1215-expose-queue-name_2023-06-29-15-54.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@snowplow/browser-tracker",
+ "comment": "Add getQueueName tracker method",
+ "type": "none"
+ }
+ ],
+ "packageName": "@snowplow/browser-tracker"
+}
\ No newline at end of file
diff --git a/libraries/browser-tracker-core/src/tracker/index.ts b/libraries/browser-tracker-core/src/tracker/index.ts
index 302dcb58e..807cd6936 100755
--- a/libraries/browser-tracker-core/src/tracker/index.ts
+++ b/libraries/browser-tracker-core/src/tracker/index.ts
@@ -1283,6 +1283,8 @@ export function Tracker(
},
clearUserData: clearUserDataAndCookies,
+
+ getQueueName: outQueue.getName,
};
return {
diff --git a/libraries/browser-tracker-core/src/tracker/out_queue.ts b/libraries/browser-tracker-core/src/tracker/out_queue.ts
index b838ba436..716d6a976 100644
--- a/libraries/browser-tracker-core/src/tracker/out_queue.ts
+++ b/libraries/browser-tracker-core/src/tracker/out_queue.ts
@@ -33,6 +33,7 @@ import { SharedState } from '../state';
import { localStorageAccessible } from '../detectors';
import { LOG, Payload } from '@snowplow/tracker-core';
import { PAYLOAD_DATA_SCHEMA } from './schemata';
+import { EventMethod } from './types';
export interface OutQueue {
enqueueRequest: (request: Payload, url: string) => void;
@@ -40,7 +41,11 @@ export interface OutQueue {
setUseLocalStorage: (localStorage: boolean) => void;
setAnonymousTracking: (anonymous: boolean) => void;
setCollectorUrl: (url: string) => void;
- setBufferSize: (bufferSize: number) => void;
+ setBufferSize: (newBufferSize: number) => void;
+ /**
+ * Returns the currently used queue name or if the `eventMethod` argument is provided, the queue name for the eventMethod.
+ */
+ getName: (eventMethod?: Exclude) => string;
}
/**
@@ -48,7 +53,7 @@ export interface OutQueue {
* Instantiated once per tracker instance.
*
* @param id - The Snowplow function name (used to generate the localStorage key)
- * @param sharedSate - Stores reference to the outbound queue so it can unload the page when all queues are empty
+ * @param sharedState - Stores reference to the outbound queue so it can unload the page when all queues are empty
* @param useLocalStorage - Whether to use localStorage at all
* @param eventMethod - if null will use 'beacon' otherwise can be set to 'post', 'get', or 'beacon' to force.
* @param postPath - The path where events are to be posted
@@ -67,7 +72,7 @@ export interface OutQueue {
*/
export function OutQueueManager(
id: string,
- sharedSate: SharedState,
+ sharedState: SharedState,
useLocalStorage: boolean,
eventMethod: string | boolean,
postPath: string,
@@ -114,7 +119,7 @@ export function OutQueueManager(
// Resolve all options and capabilities and decide path
path = usePost ? postPath : '/i',
// Different queue names for GET and POST since they are stored differently
- queueName = `snowplowOutQueue_${id}_${usePost ? 'post2' : 'get'}`;
+ queueName = getQueueName(id, usePost ? 'post' : 'get');
// Ensure we don't set headers when beacon is the requested eventMethod as we might fallback to POST
// and end up sending them in older browsers which don't support beacon leading to inconsistencies
@@ -128,7 +133,9 @@ export function OutQueueManager(
try {
const localStorageQueue = window.localStorage.getItem(queueName);
outQueue = localStorageQueue ? JSON.parse(localStorageQueue) : [];
- } catch (e) {}
+ } catch (e) {
+ LOG.error('Failed to access window.localStorage queue.');
+ }
}
// Initialize to and empty array if we didn't get anything out of localStorage
@@ -137,16 +144,20 @@ export function OutQueueManager(
}
// Used by pageUnloadGuard
- sharedSate.outQueues.push(outQueue);
+ sharedState.outQueues.push(outQueue);
if (useXhr && bufferSize > 1) {
- sharedSate.bufferFlushers.push(function (sync) {
+ sharedState.bufferFlushers.push(function (sync) {
if (!executingQueue) {
executeQueue(sync);
}
});
}
+ function getQueueName(id: string, method: Exclude) {
+ return `snowplowOutQueue_${id}_${method === 'post' ? 'post2' : 'get'}`;
+ }
+
/*
* Convert a dictionary to a querystring
* The context field is the last in the querystring
@@ -535,6 +546,7 @@ export function OutQueueManager(
setBufferSize: (newBufferSize: number) => {
bufferSize = newBufferSize;
},
+ getName: (method?: Exclude) => (method ? getQueueName(id, method) : queueName),
};
function hasWebKitBeaconBug(useragent: string) {
diff --git a/libraries/browser-tracker-core/src/tracker/types.ts b/libraries/browser-tracker-core/src/tracker/types.ts
index b45f5f8fe..6c0608ccc 100755
--- a/libraries/browser-tracker-core/src/tracker/types.ts
+++ b/libraries/browser-tracker-core/src/tracker/types.ts
@@ -580,6 +580,11 @@ export interface BrowserTracker {
*/
clearUserData: (configuration?: ClearUserDataConfiguration) => void;
+ /**
+ * Returns the currently used queue name or if the `eventMethod` argument is provided, the queue name for the eventMethod.
+ */
+ getQueueName: (eventMethod?: 'post' | 'get' | undefined) => string;
+
/**
* Add a plugin into the plugin collection after Tracker has already been initialised
* @param configuration - The plugin to add
diff --git a/libraries/browser-tracker-core/test/out_queue.test.ts b/libraries/browser-tracker-core/test/out_queue.test.ts
index c51b71194..d6a794120 100644
--- a/libraries/browser-tracker-core/test/out_queue.test.ts
+++ b/libraries/browser-tracker-core/test/out_queue.test.ts
@@ -57,6 +57,54 @@ describe('OutQueueManager', () => {
(xhrMock as any).onreadystatechange();
};
+ describe('API', () => {
+ it('returns the correct queue name', () => {
+ const postOutQueue = OutQueueManager(
+ 'sp',
+ new SharedState(),
+ true,
+ 'post',
+ '/com.snowplowanalytics.snowplow/tp2',
+ 1,
+ 40000,
+ 0, // maxGetBytes – 0 for no limit
+ false,
+ maxQueueSize,
+ 5000,
+ false,
+ {},
+ true,
+ [401], // retry status codes - override don't retry ones
+ [401, 505] // don't retry status codes
+ );
+
+ expect(postOutQueue.getName()).toBe('snowplowOutQueue_sp_post2');
+ expect(postOutQueue.getName('get')).toBe('snowplowOutQueue_sp_get');
+
+ const getOutQueue = OutQueueManager(
+ 'sp',
+ new SharedState(),
+ true,
+ 'get',
+ '/com.snowplowanalytics.snowplow/tp2',
+ 1,
+ 40000,
+ 0,
+ false,
+ maxQueueSize,
+ 5000,
+ false,
+ {},
+ true,
+ [],
+ []
+ );
+
+ expect(getOutQueue.getName()).toBe('snowplowOutQueue_sp_get');
+ expect(getOutQueue.getName('post')).toBe('snowplowOutQueue_sp_post2');
+ });
+ });
+
describe('POST requests', () => {
var outQueue: OutQueue;
diff --git a/trackers/browser-tracker/docs/browser-tracker.api.md b/trackers/browser-tracker/docs/browser-tracker.api.md
index 3d7214028..86015a0ed 100644
--- a/trackers/browser-tracker/docs/browser-tracker.api.md
+++ b/trackers/browser-tracker/docs/browser-tracker.api.md
@@ -75,6 +75,7 @@ export interface BrowserTracker {
getDomainUserId: () => void;
getDomainUserInfo: () => void;
getPageViewId: () => string;
+ getQueueName: (eventMethod?: "post" | "get" | undefined) => string;
getTabId: () => string | null;
getUserId: () => void;
id: string;
diff --git a/trackers/browser-tracker/test/helpers/index.ts b/trackers/browser-tracker/test/helpers/index.ts
new file mode 100644
index 000000000..8745733a0
--- /dev/null
+++ b/trackers/browser-tracker/test/helpers/index.ts
@@ -0,0 +1,6 @@
+import { SharedState, TrackerConfiguration, addTracker } from '@snowplow/browser-tracker-core';
+
+export function createTracker(configuration?: TrackerConfiguration) {
+ const id = 'sp-' + Math.random();
+ return addTracker(id, id, '', '', new SharedState(), configuration);
+}
diff --git a/trackers/browser-tracker/test/tracker.test.ts b/trackers/browser-tracker/test/tracker.test.ts
index b26982afd..38181a1dd 100644
--- a/trackers/browser-tracker/test/tracker.test.ts
+++ b/trackers/browser-tracker/test/tracker.test.ts
@@ -30,6 +30,7 @@
import { SharedState, addTracker } from '@snowplow/browser-tracker-core';
import F from 'lodash/fp';
+import { createTracker } from './helpers';
jest.useFakeTimers('modern');
@@ -276,3 +277,24 @@ describe('Activity tracker behaviour', () => {
expect(secondPageId).toBe(extractPageId(ppl));
});
});
+
+describe('API', () => {
+ it('getQueueName does return the queue name', () => {
+ let rand = Math.random();
+ const mathSpy = jest.spyOn(global.Math, 'random');
+ mathSpy.mockReturnValueOnce(rand);
+
+ const postTracker = createTracker();
+ expect(postTracker?.getQueueName()).toBe(`snowplowOutQueue_sp-${rand}_post2`);
+ expect(postTracker?.getQueueName('get')).toBe(`snowplowOutQueue_sp-${rand}_get`);
+
+ rand = Math.random();
+ mathSpy.mockReturnValueOnce(rand);
+
+ const getTracker = createTracker({ eventMethod: 'get' });
+ expect(getTracker?.getQueueName()).toBe(`snowplowOutQueue_sp-${rand}_get`);
+ expect(getTracker?.getQueueName('post')).toBe(`snowplowOutQueue_sp-${rand}_post2`);
+
+ mathSpy.mockRestore();
+ });
+});