@sockethub/data-layer 1.0.0-alpha.10 → 1.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +50335 -29187
- package/dist/index.js.map +320 -598
- package/package.json +11 -9
- package/src/credentials-store.test.ts +18 -2
- package/src/credentials-store.ts +82 -14
- package/src/index.ts +13 -4
- package/src/job-base.ts +74 -7
- package/src/job-queue.test.ts +25 -10
- package/src/job-queue.ts +53 -33
- package/src/job-worker.test.ts +17 -3
- package/src/job-worker.ts +35 -16
- package/src/queue-id.test.ts +17 -0
- package/src/queue-id.ts +14 -0
- package/src/types.ts +4 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sockethub/data-layer",
|
|
3
3
|
"description": "Storing and RPC of data for Sockethub",
|
|
4
|
-
"version": "1.0.0-alpha.
|
|
4
|
+
"version": "1.0.0-alpha.12",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"author": "Nick Jennings <nick@silverbucket.net>",
|
|
@@ -41,25 +41,27 @@
|
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "bun build src/index.ts --outdir dist --target node --format esm --sourcemap=external",
|
|
43
43
|
"clean": "rm -rf dist",
|
|
44
|
+
"clean:deps": "rm -rf node_modules",
|
|
44
45
|
"doc": "typedoc --options typedoc.json",
|
|
45
46
|
"test": "bun test src/",
|
|
46
|
-
"test:integration": "
|
|
47
|
+
"test:integration": "bun test ./integration/redis.integration.ts"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@sockethub/crypto": "^1.0.0-alpha.
|
|
50
|
-
"@sockethub/
|
|
50
|
+
"@sockethub/crypto": "^1.0.0-alpha.12",
|
|
51
|
+
"@sockethub/logger": "^1.0.0-alpha.12",
|
|
52
|
+
"@sockethub/schemas": "^3.0.0-alpha.12",
|
|
51
53
|
"bullmq": "^5.66.5",
|
|
52
|
-
"debug": "^4.4.3",
|
|
53
54
|
"ioredis": "^5.9.2",
|
|
54
|
-
"secure-store-redis": "^
|
|
55
|
+
"secure-store-redis": "^4.1.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@types/bun": "latest",
|
|
58
|
-
"@types/debug": "^4.1.12",
|
|
59
59
|
"@types/sinon": "^17.0.4",
|
|
60
|
+
"@types/winston": "^2.4.4",
|
|
60
61
|
"sinon": "^17.0.2",
|
|
61
62
|
"typedoc": "^0.28.16",
|
|
62
|
-
"typedoc-plugin-markdown": "^4.9.0"
|
|
63
|
+
"typedoc-plugin-markdown": "^4.9.0",
|
|
64
|
+
"winston": "^3.19.0"
|
|
63
65
|
},
|
|
64
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "f039dab3c3f67cbbf204476fc397532e973f82a8"
|
|
65
67
|
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from "bun:test";
|
|
2
2
|
import * as sinon from "sinon";
|
|
3
3
|
|
|
4
|
+
import type { Logger } from "@sockethub/schemas";
|
|
5
|
+
|
|
4
6
|
import { CredentialsStore } from "./credentials-store";
|
|
5
7
|
|
|
8
|
+
const mockLogger: Logger = {
|
|
9
|
+
error: () => {},
|
|
10
|
+
warn: () => {},
|
|
11
|
+
info: () => {},
|
|
12
|
+
debug: () => {},
|
|
13
|
+
};
|
|
14
|
+
|
|
6
15
|
describe("CredentialsStore", () => {
|
|
7
16
|
let credentialsStore,
|
|
8
17
|
MockSecureStore,
|
|
@@ -16,6 +25,8 @@ describe("CredentialsStore", () => {
|
|
|
16
25
|
MockSecureStore = sinon.stub().returns({
|
|
17
26
|
get: MockStoreGet,
|
|
18
27
|
save: MockStoreSave,
|
|
28
|
+
isConnected: true,
|
|
29
|
+
connect: sinon.stub().resolves(),
|
|
19
30
|
});
|
|
20
31
|
class TestCredentialsStore extends CredentialsStore {
|
|
21
32
|
initCrypto() {
|
|
@@ -34,6 +45,7 @@ describe("CredentialsStore", () => {
|
|
|
34
45
|
"a session id",
|
|
35
46
|
"a secret must be 32 chars and th",
|
|
36
47
|
{ url: "redis config" },
|
|
48
|
+
mockLogger,
|
|
37
49
|
);
|
|
38
50
|
});
|
|
39
51
|
|
|
@@ -42,11 +54,15 @@ describe("CredentialsStore", () => {
|
|
|
42
54
|
sinon.assert.calledWith(MockSecureStore, {
|
|
43
55
|
namespace: "foo",
|
|
44
56
|
secret: "a secret must be 32 chars and th",
|
|
45
|
-
redis: {
|
|
57
|
+
redis: {
|
|
58
|
+
url: "redis config",
|
|
59
|
+
connectionName:
|
|
60
|
+
"data-layer:credentials-store:a parent id:a session id",
|
|
61
|
+
},
|
|
46
62
|
});
|
|
47
63
|
expect(typeof credentialsStore).toEqual("object");
|
|
48
64
|
expect(credentialsStore.uid).toEqual(
|
|
49
|
-
`sockethub:data-layer:credentials-store:a
|
|
65
|
+
`sockethub:a parent id:data-layer:credentials-store:a session id`,
|
|
50
66
|
);
|
|
51
67
|
expect(typeof credentialsStore.get).toEqual("function");
|
|
52
68
|
expect(typeof credentialsStore.save).toEqual("function");
|
package/src/credentials-store.ts
CHANGED
|
@@ -1,10 +1,58 @@
|
|
|
1
1
|
import { crypto } from "@sockethub/crypto";
|
|
2
|
+
import {
|
|
3
|
+
createLogger,
|
|
4
|
+
getLoggerNamespace,
|
|
5
|
+
type Logger,
|
|
6
|
+
} from "@sockethub/logger";
|
|
2
7
|
import type { CredentialsObject } from "@sockethub/schemas";
|
|
3
|
-
import
|
|
8
|
+
import IORedis, { type Redis } from "ioredis";
|
|
4
9
|
import SecureStore from "secure-store-redis";
|
|
5
10
|
|
|
11
|
+
import { buildCredentialsStoreId } from "./queue-id.js";
|
|
6
12
|
import type { RedisConfig } from "./types.js";
|
|
7
13
|
|
|
14
|
+
let sharedCredentialsRedisConnection: Redis | null = null;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates or returns a shared Redis connection for CredentialsStore instances.
|
|
18
|
+
* This prevents connection exhaustion by reusing a single connection across
|
|
19
|
+
* all credential storage operations.
|
|
20
|
+
*
|
|
21
|
+
* @param config - Redis configuration
|
|
22
|
+
* @returns Shared Redis connection instance
|
|
23
|
+
*/
|
|
24
|
+
export function createCredentialsRedisConnection(config: RedisConfig): Redis {
|
|
25
|
+
if (!sharedCredentialsRedisConnection) {
|
|
26
|
+
sharedCredentialsRedisConnection = new IORedis(config.url, {
|
|
27
|
+
connectionName: config.connectionName,
|
|
28
|
+
enableOfflineQueue: false,
|
|
29
|
+
maxRetriesPerRequest: config.maxRetriesPerRequest ?? null,
|
|
30
|
+
connectTimeout: config.connectTimeout ?? 10000,
|
|
31
|
+
disconnectTimeout: config.disconnectTimeout ?? 5000,
|
|
32
|
+
lazyConnect: false,
|
|
33
|
+
retryStrategy: (times: number) => {
|
|
34
|
+
if (times > 3) return null;
|
|
35
|
+
return Math.min(2 ** (times - 1) * 200, 2000);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return sharedCredentialsRedisConnection;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resets the shared credentials Redis connection. Used primarily for testing.
|
|
44
|
+
*/
|
|
45
|
+
export async function resetSharedCredentialsRedisConnection(): Promise<void> {
|
|
46
|
+
if (sharedCredentialsRedisConnection) {
|
|
47
|
+
try {
|
|
48
|
+
sharedCredentialsRedisConnection.disconnect(false);
|
|
49
|
+
} catch (_err) {
|
|
50
|
+
// Ignore disconnect errors during cleanup
|
|
51
|
+
}
|
|
52
|
+
sharedCredentialsRedisConnection = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
8
56
|
export interface CredentialsStoreInterface {
|
|
9
57
|
get(
|
|
10
58
|
actor: string,
|
|
@@ -14,13 +62,16 @@ export interface CredentialsStoreInterface {
|
|
|
14
62
|
}
|
|
15
63
|
|
|
16
64
|
export async function verifySecureStore(config: RedisConfig): Promise<void> {
|
|
17
|
-
const log =
|
|
65
|
+
const log = createLogger("data-layer:verify-secure-store");
|
|
66
|
+
const sharedClient = createCredentialsRedisConnection(config);
|
|
18
67
|
const ss = new SecureStore({
|
|
19
|
-
|
|
68
|
+
uid: "data-layer:verify",
|
|
69
|
+
secret: "aB3#xK9mP2qR7wZ4cT8nY6vH1jL5fD0s",
|
|
70
|
+
redis: { client: sharedClient },
|
|
20
71
|
});
|
|
21
|
-
await ss.
|
|
72
|
+
await ss.connect();
|
|
22
73
|
await ss.disconnect();
|
|
23
|
-
log("
|
|
74
|
+
log.info("secure store connection verified");
|
|
24
75
|
}
|
|
25
76
|
|
|
26
77
|
/**
|
|
@@ -49,7 +100,7 @@ export class CredentialsStore implements CredentialsStoreInterface {
|
|
|
49
100
|
readonly uid: string;
|
|
50
101
|
store: SecureStore;
|
|
51
102
|
objectHash: (o: unknown) => string;
|
|
52
|
-
private readonly log:
|
|
103
|
+
private readonly log: Logger;
|
|
53
104
|
|
|
54
105
|
/**
|
|
55
106
|
* Creates a new CredentialsStore instance.
|
|
@@ -71,11 +122,19 @@ export class CredentialsStore implements CredentialsStoreInterface {
|
|
|
71
122
|
"CredentialsStore secret must be 32 chars in length",
|
|
72
123
|
);
|
|
73
124
|
}
|
|
74
|
-
|
|
75
|
-
this.log =
|
|
125
|
+
// Create logger with full namespace (context will be prepended automatically)
|
|
126
|
+
this.log = createLogger(
|
|
127
|
+
`data-layer:credentials-store:${parentId}:${sessionId}`,
|
|
128
|
+
);
|
|
129
|
+
|
|
76
130
|
this.initCrypto();
|
|
131
|
+
|
|
132
|
+
// Use the canonical, context-free namespace for credentials storage keys
|
|
133
|
+
this.uid = buildCredentialsStoreId(parentId, sessionId);
|
|
134
|
+
// Keep full logger namespace for Redis connection naming
|
|
135
|
+
redisConfig.connectionName = getLoggerNamespace(this.log);
|
|
77
136
|
this.initSecureStore(secret, redisConfig);
|
|
78
|
-
this.log("initialized");
|
|
137
|
+
this.log.debug("initialized");
|
|
79
138
|
}
|
|
80
139
|
|
|
81
140
|
initCrypto() {
|
|
@@ -83,23 +142,29 @@ export class CredentialsStore implements CredentialsStoreInterface {
|
|
|
83
142
|
}
|
|
84
143
|
|
|
85
144
|
initSecureStore(secret: string, redisConfig: RedisConfig) {
|
|
145
|
+
// Use shared Redis connection for connection pooling
|
|
146
|
+
const sharedClient = createCredentialsRedisConnection(redisConfig);
|
|
86
147
|
this.store = new SecureStore({
|
|
87
148
|
uid: this.uid,
|
|
88
149
|
secret: secret,
|
|
89
|
-
redis:
|
|
150
|
+
redis: { client: sharedClient },
|
|
90
151
|
});
|
|
91
152
|
}
|
|
92
153
|
|
|
93
154
|
/**
|
|
94
|
-
* Gets the credentials for a given actor ID
|
|
155
|
+
* Gets the credentials for a given actor ID.
|
|
95
156
|
* @param actor
|
|
96
|
-
* @param credentialsHash - Optional hash to validate credentials.
|
|
157
|
+
* @param credentialsHash - Optional hash to validate credentials.
|
|
158
|
+
* If undefined, validation is skipped.
|
|
97
159
|
*/
|
|
98
160
|
async get(
|
|
99
161
|
actor: string,
|
|
100
162
|
credentialsHash: string | undefined,
|
|
101
163
|
): Promise<CredentialsObject> {
|
|
102
|
-
this.log(`get credentials for ${actor}`);
|
|
164
|
+
this.log.debug(`get credentials for ${actor}`);
|
|
165
|
+
if (!this.store.isConnected) {
|
|
166
|
+
await this.store.connect();
|
|
167
|
+
}
|
|
103
168
|
const credentials: CredentialsObject = await this.store.get(actor);
|
|
104
169
|
if (!credentials) {
|
|
105
170
|
throw new Error(`credentials not found for ${actor}`);
|
|
@@ -119,6 +184,9 @@ export class CredentialsStore implements CredentialsStoreInterface {
|
|
|
119
184
|
* @param creds
|
|
120
185
|
*/
|
|
121
186
|
async save(actor: string, creds: CredentialsObject): Promise<number> {
|
|
122
|
-
|
|
187
|
+
if (!this.store.isConnected) {
|
|
188
|
+
await this.store.connect();
|
|
189
|
+
}
|
|
190
|
+
return await this.store.save(actor, creds);
|
|
123
191
|
}
|
|
124
192
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createLogger } from "@sockethub/logger";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
CredentialsStore,
|
|
5
5
|
type CredentialsStoreInterface,
|
|
6
|
+
resetSharedCredentialsRedisConnection,
|
|
6
7
|
verifySecureStore,
|
|
7
8
|
} from "./credentials-store.js";
|
|
9
|
+
import {
|
|
10
|
+
getRedisConnectionCount,
|
|
11
|
+
resetSharedRedisConnection,
|
|
12
|
+
} from "./job-base.js";
|
|
8
13
|
import { JobQueue, verifyJobQueue } from "./job-queue.js";
|
|
9
14
|
import { JobWorker } from "./job-worker.js";
|
|
15
|
+
|
|
10
16
|
export * from "./types.js";
|
|
11
|
-
import type { RedisConfig } from "./types.js";
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
import type { RedisConfig } from "./types.js";
|
|
14
19
|
|
|
15
20
|
async function redisCheck(config: RedisConfig): Promise<void> {
|
|
16
|
-
log(
|
|
21
|
+
const log = createLogger("data-layer:redis-check");
|
|
22
|
+
log.debug(`checking redis connection ${config.url}`);
|
|
17
23
|
await verifySecureStore(config);
|
|
18
24
|
await verifyJobQueue(config);
|
|
19
25
|
}
|
|
@@ -23,5 +29,8 @@ export {
|
|
|
23
29
|
JobQueue,
|
|
24
30
|
JobWorker,
|
|
25
31
|
CredentialsStore,
|
|
32
|
+
getRedisConnectionCount,
|
|
33
|
+
resetSharedRedisConnection,
|
|
34
|
+
resetSharedCredentialsRedisConnection,
|
|
26
35
|
type CredentialsStoreInterface,
|
|
27
36
|
};
|
package/src/job-base.ts
CHANGED
|
@@ -1,16 +1,83 @@
|
|
|
1
1
|
import EventEmitter from "node:events";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { crypto, type Crypto } from "@sockethub/crypto";
|
|
2
|
+
import { type Crypto, crypto } from "@sockethub/crypto";
|
|
5
3
|
import type { ActivityStream } from "@sockethub/schemas";
|
|
4
|
+
import IORedis, { type Redis } from "ioredis";
|
|
6
5
|
|
|
7
6
|
import type { JobDataDecrypted, JobEncrypted, RedisConfig } from "./types.js";
|
|
8
7
|
|
|
8
|
+
let sharedRedisConnection: Redis | null = null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates or returns a shared Redis connection to enable connection pooling.
|
|
12
|
+
* This prevents connection exhaustion under high load by reusing a single
|
|
13
|
+
* connection across all JobQueue and JobWorker instances.
|
|
14
|
+
*
|
|
15
|
+
* @param config - Redis configuration with optional timeout and retry settings
|
|
16
|
+
* @returns Shared Redis connection instance
|
|
17
|
+
*/
|
|
9
18
|
export function createIORedisConnection(config: RedisConfig): Redis {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
if (!sharedRedisConnection) {
|
|
20
|
+
sharedRedisConnection = new IORedis(config.url, {
|
|
21
|
+
connectionName: config.connectionName,
|
|
22
|
+
enableOfflineQueue: false,
|
|
23
|
+
maxRetriesPerRequest: config.maxRetriesPerRequest ?? null,
|
|
24
|
+
connectTimeout: config.connectTimeout ?? 10000,
|
|
25
|
+
disconnectTimeout: config.disconnectTimeout ?? 5000,
|
|
26
|
+
lazyConnect: false,
|
|
27
|
+
retryStrategy: (times: number) => {
|
|
28
|
+
// Stop retrying after 3 attempts to fail fast
|
|
29
|
+
if (times > 3) return null;
|
|
30
|
+
// Exponential backoff: 200ms, 400ms, 800ms
|
|
31
|
+
return Math.min(2 ** (times - 1) * 200, 2000);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return sharedRedisConnection;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resets the shared Redis connection. Used primarily for testing.
|
|
40
|
+
* Disconnects the current connection before resetting.
|
|
41
|
+
*/
|
|
42
|
+
export async function resetSharedRedisConnection(): Promise<void> {
|
|
43
|
+
if (sharedRedisConnection) {
|
|
44
|
+
try {
|
|
45
|
+
sharedRedisConnection.disconnect(false);
|
|
46
|
+
} catch (_err) {
|
|
47
|
+
// Ignore disconnect errors during cleanup
|
|
48
|
+
}
|
|
49
|
+
sharedRedisConnection = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Gets the total number of active Redis client connections.
|
|
55
|
+
*
|
|
56
|
+
* Note: This queries the Redis server directly using CLIENT LIST and reports
|
|
57
|
+
* ALL active connections to the Redis instance. This includes connections from
|
|
58
|
+
* Sockethub (BullMQ queues, workers, and the shared connection) as well as any
|
|
59
|
+
* other applications or services connected to the same Redis server.
|
|
60
|
+
*
|
|
61
|
+
* @returns Number of active Redis connections, or 0 if no connection exists
|
|
62
|
+
*/
|
|
63
|
+
export async function getRedisConnectionCount(): Promise<number> {
|
|
64
|
+
if (!sharedRedisConnection) {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const clientList = (await sharedRedisConnection.client(
|
|
70
|
+
"LIST",
|
|
71
|
+
)) as string;
|
|
72
|
+
// CLIENT LIST returns one line per connection, filter out empty lines
|
|
73
|
+
const connections = clientList
|
|
74
|
+
.split("\n")
|
|
75
|
+
.filter((line: string) => line.trim());
|
|
76
|
+
return connections.length;
|
|
77
|
+
} catch (_err) {
|
|
78
|
+
// Return 0 if Redis query fails (connection issues, etc.)
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
14
81
|
}
|
|
15
82
|
|
|
16
83
|
export class JobBase extends EventEmitter {
|
package/src/job-queue.test.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { expect } from "chai";
|
|
2
2
|
import * as sinon from "sinon";
|
|
3
3
|
|
|
4
|
+
import type { Logger } from "@sockethub/schemas";
|
|
5
|
+
|
|
4
6
|
import { JobQueue } from "./index";
|
|
5
7
|
|
|
8
|
+
const mockLogger: Logger = {
|
|
9
|
+
error: () => {},
|
|
10
|
+
warn: () => {},
|
|
11
|
+
info: () => {},
|
|
12
|
+
debug: () => {},
|
|
13
|
+
};
|
|
14
|
+
|
|
6
15
|
describe("JobQueue", () => {
|
|
7
16
|
let MockBull, jobQueue, cryptoMocks, sandbox;
|
|
8
17
|
|
|
@@ -31,17 +40,22 @@ describe("JobQueue", () => {
|
|
|
31
40
|
|
|
32
41
|
class TestJobQueue extends JobQueue {
|
|
33
42
|
init() {
|
|
43
|
+
// BullMQ v5+ prohibits colons in queue names, so replace with dashes
|
|
44
|
+
const queueName = this.queueId.replace(/:/g, "-");
|
|
34
45
|
this.redisConnection = MockBull();
|
|
35
|
-
this.queue = MockBull(
|
|
46
|
+
this.queue = MockBull(queueName, {
|
|
36
47
|
connection: this.redisConnection,
|
|
37
48
|
});
|
|
38
|
-
this.events = MockBull(
|
|
49
|
+
this.events = MockBull(queueName, {
|
|
39
50
|
connection: this.redisConnection,
|
|
40
51
|
});
|
|
41
52
|
}
|
|
42
53
|
initCrypto() {
|
|
43
54
|
this.crypto = cryptoMocks;
|
|
44
55
|
}
|
|
56
|
+
getQueueId() {
|
|
57
|
+
return this.queueId;
|
|
58
|
+
}
|
|
45
59
|
}
|
|
46
60
|
jobQueue = new TestJobQueue(
|
|
47
61
|
"a parent id",
|
|
@@ -50,6 +64,7 @@ describe("JobQueue", () => {
|
|
|
50
64
|
{
|
|
51
65
|
url: "redis config",
|
|
52
66
|
},
|
|
67
|
+
mockLogger,
|
|
53
68
|
);
|
|
54
69
|
jobQueue.emit = sandbox.stub();
|
|
55
70
|
});
|
|
@@ -63,14 +78,14 @@ describe("JobQueue", () => {
|
|
|
63
78
|
sinon.assert.calledThrice(MockBull);
|
|
64
79
|
sinon.assert.calledWith(
|
|
65
80
|
MockBull,
|
|
66
|
-
"sockethub
|
|
81
|
+
"sockethub-a parent id-data-layer-queue-a session id",
|
|
67
82
|
{
|
|
68
83
|
connection: MockBull(),
|
|
69
84
|
},
|
|
70
85
|
);
|
|
71
86
|
expect(typeof jobQueue).to.equal("object");
|
|
72
|
-
expect(jobQueue.
|
|
73
|
-
`sockethub:data-layer:queue:a
|
|
87
|
+
expect(jobQueue.getQueueId()).to.equal(
|
|
88
|
+
`sockethub:a parent id:data-layer:queue:a session id`,
|
|
74
89
|
);
|
|
75
90
|
expect(typeof jobQueue.add).to.equal("function");
|
|
76
91
|
expect(typeof jobQueue.getJob).to.equal("function");
|
|
@@ -93,7 +108,7 @@ describe("JobQueue", () => {
|
|
|
93
108
|
it("returns expected job format", () => {
|
|
94
109
|
cryptoMocks.encrypt.returns("an encrypted message");
|
|
95
110
|
const job = jobQueue.createJob("a socket id", {
|
|
96
|
-
|
|
111
|
+
platform: "some context",
|
|
97
112
|
id: "an identifier",
|
|
98
113
|
});
|
|
99
114
|
expect(job).to.eql({
|
|
@@ -106,7 +121,7 @@ describe("JobQueue", () => {
|
|
|
106
121
|
it("uses counter when no id provided", () => {
|
|
107
122
|
cryptoMocks.encrypt.returns("an encrypted message");
|
|
108
123
|
let job = jobQueue.createJob("a socket id", {
|
|
109
|
-
|
|
124
|
+
platform: "some context",
|
|
110
125
|
});
|
|
111
126
|
expect(job).to.eql({
|
|
112
127
|
title: "some context-0",
|
|
@@ -114,7 +129,7 @@ describe("JobQueue", () => {
|
|
|
114
129
|
sessionId: "a socket id",
|
|
115
130
|
});
|
|
116
131
|
job = jobQueue.createJob("a socket id", {
|
|
117
|
-
|
|
132
|
+
platform: "some context",
|
|
118
133
|
});
|
|
119
134
|
expect(job).to.eql({
|
|
120
135
|
title: "some context-1",
|
|
@@ -186,7 +201,7 @@ describe("JobQueue", () => {
|
|
|
186
201
|
msg: "encrypted foo",
|
|
187
202
|
};
|
|
188
203
|
const res = await jobQueue.add("a socket id", {
|
|
189
|
-
|
|
204
|
+
platform: "a platform",
|
|
190
205
|
id: "an identifier",
|
|
191
206
|
});
|
|
192
207
|
sinon.assert.calledOnce(jobQueue.queue.isPaused);
|
|
@@ -207,7 +222,7 @@ describe("JobQueue", () => {
|
|
|
207
222
|
jobQueue.queue.isPaused.returns(true);
|
|
208
223
|
try {
|
|
209
224
|
await jobQueue.add("a socket id", {
|
|
210
|
-
|
|
225
|
+
platform: "a platform",
|
|
211
226
|
id: "an identifier",
|
|
212
227
|
});
|
|
213
228
|
} catch (err) {
|