@budibase/backend-core 3.2.0 → 3.2.1

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.
Files changed (34) hide show
  1. package/dist/index.js +1986 -1348
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +4 -4
  5. package/dist/plugins.js.meta.json +1 -1
  6. package/dist/src/queue/inMemoryQueue.d.ts +0 -2
  7. package/dist/src/queue/inMemoryQueue.js +1 -11
  8. package/dist/src/queue/inMemoryQueue.js.map +1 -1
  9. package/dist/src/queue/queue.js +6 -0
  10. package/dist/src/queue/queue.js.map +1 -1
  11. package/dist/tests/core/utilities/index.d.ts +1 -0
  12. package/dist/tests/core/utilities/index.js +2 -1
  13. package/dist/tests/core/utilities/index.js.map +1 -1
  14. package/dist/tests/core/utilities/queue.d.ts +2 -0
  15. package/dist/tests/core/utilities/queue.js +21 -0
  16. package/dist/tests/core/utilities/queue.js.map +1 -0
  17. package/dist/tests/core/utilities/testContainerUtils.d.ts +2 -0
  18. package/dist/tests/core/utilities/testContainerUtils.js +63 -0
  19. package/dist/tests/core/utilities/testContainerUtils.js.map +1 -1
  20. package/dist/tests/core/utilities/utils/index.d.ts +1 -0
  21. package/dist/tests/core/utilities/utils/index.js +2 -1
  22. package/dist/tests/core/utilities/utils/index.js.map +1 -1
  23. package/dist/tests/core/utilities/utils/queue.d.ts +3 -0
  24. package/dist/tests/core/utilities/utils/queue.js +37 -0
  25. package/dist/tests/core/utilities/utils/queue.js.map +1 -0
  26. package/package.json +4 -4
  27. package/src/cache/tests/docWritethrough.spec.ts +26 -24
  28. package/src/queue/inMemoryQueue.ts +2 -12
  29. package/src/queue/queue.ts +10 -3
  30. package/tests/core/utilities/index.ts +1 -0
  31. package/tests/core/utilities/queue.ts +9 -0
  32. package/tests/core/utilities/testContainerUtils.ts +57 -0
  33. package/tests/core/utilities/utils/index.ts +1 -0
  34. package/tests/core/utilities/utils/queue.ts +27 -0
@@ -1,11 +1,22 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.getContainerByImage = getContainerByImage;
4
13
  exports.getContainerById = getContainerById;
5
14
  exports.getExposedV4Ports = getExposedV4Ports;
6
15
  exports.getExposedV4Port = getExposedV4Port;
7
16
  exports.setupEnv = setupEnv;
17
+ exports.startContainer = startContainer;
8
18
  const child_process_1 = require("child_process");
19
+ const lodash_1 = require("lodash");
9
20
  const IPV4_PORT_REGEX = new RegExp(`0\\.0\\.0\\.0:(\\d+)->(\\d+)/tcp`, "g");
10
21
  function getTestcontainers() {
11
22
  // We use --format json to make sure the output is nice and machine-readable,
@@ -76,4 +87,56 @@ function setupEnv(...envs) {
76
87
  }
77
88
  }
78
89
  }
90
+ function startContainer(container) {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ const imageName = container.imageName.string;
93
+ let key = imageName;
94
+ if (imageName.includes("@sha256")) {
95
+ key = imageName.split("@")[0];
96
+ }
97
+ key = key.replace(/\//g, "-").replace(/:/g, "-");
98
+ container = container
99
+ .withReuse()
100
+ .withLabels({ "com.budibase": "true" })
101
+ .withName(`${key}_testcontainer`);
102
+ let startedContainer = undefined;
103
+ let lastError = undefined;
104
+ for (let i = 0; i < 10; i++) {
105
+ try {
106
+ // container.start() is not an idempotent operation, calling `start`
107
+ // modifies the internal state of a GenericContainer instance such that
108
+ // the hash it uses to determine reuse changes. We need to clone the
109
+ // container before calling start to ensure that we're using the same
110
+ // reuse hash every time.
111
+ const containerCopy = (0, lodash_1.cloneDeep)(container);
112
+ startedContainer = yield containerCopy.start();
113
+ lastError = undefined;
114
+ break;
115
+ }
116
+ catch (e) {
117
+ lastError = e;
118
+ yield new Promise(resolve => setTimeout(resolve, 1000));
119
+ }
120
+ }
121
+ if (!startedContainer) {
122
+ if (lastError) {
123
+ throw lastError;
124
+ }
125
+ throw new Error(`failed to start container: ${imageName}`);
126
+ }
127
+ const info = getContainerById(startedContainer.getId());
128
+ if (!info) {
129
+ throw new Error("Container not found");
130
+ }
131
+ // Some Docker runtimes, when you expose a port, will bind it to both
132
+ // 127.0.0.1 and ::1, so ipv4 and ipv6. The port spaces of ipv4 and ipv6
133
+ // addresses are not shared, and testcontainers will sometimes give you back
134
+ // the ipv6 port. There's no way to know that this has happened, and if you
135
+ // try to then connect to `localhost:port` you may attempt to bind to the v4
136
+ // address which could be unbound or even an entirely different container. For
137
+ // that reason, we don't use testcontainers' `getExposedPort` function,
138
+ // preferring instead our own method that guaranteed v4 ports.
139
+ return getExposedV4Ports(info);
140
+ });
141
+ }
79
142
  //# sourceMappingURL=testContainerUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testContainerUtils.js","sourceRoot":"","sources":["../../../../tests/core/utilities/testContainerUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testContainerUtils.js","sourceRoot":"","sources":["../../../../tests/core/utilities/testContainerUtils.ts"],"names":[],"mappings":"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"}
@@ -1 +1,2 @@
1
1
  export * as time from "./time";
2
+ export * as queue from "./queue";
@@ -23,6 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.time = void 0;
26
+ exports.queue = exports.time = void 0;
27
27
  exports.time = __importStar(require("./time"));
28
+ exports.queue = __importStar(require("./queue"));
28
29
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../tests/core/utilities/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAA8B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../tests/core/utilities/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAA8B;AAC9B,iDAAgC"}
@@ -0,0 +1,3 @@
1
+ import { Queue } from "bull";
2
+ export declare function useRealQueues(): Promise<void>;
3
+ export declare function processMessages(queue: Queue): Promise<void>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.useRealQueues = useRealQueues;
13
+ exports.processMessages = processMessages;
14
+ const testcontainers_1 = require("testcontainers");
15
+ const testContainerUtils_1 = require("../testContainerUtils");
16
+ function useRealQueues() {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ var _a;
19
+ const ports = yield (0, testContainerUtils_1.startContainer)(new testcontainers_1.GenericContainer("redis")
20
+ .withExposedPorts(6379)
21
+ .withWaitStrategy(testcontainers_1.Wait.forSuccessfulCommand(`redis-cli`).withStartupTimeout(10000)));
22
+ const port = (_a = ports.find(x => x.container === 6379)) === null || _a === void 0 ? void 0 : _a.host;
23
+ if (!port) {
24
+ throw new Error("Redis port not found");
25
+ }
26
+ process.env.BULL_TEST_REDIS_PORT = port.toString();
27
+ });
28
+ }
29
+ function processMessages(queue) {
30
+ return __awaiter(this, void 0, void 0, function* () {
31
+ do {
32
+ yield queue.whenCurrentJobsFinished();
33
+ } while (yield queue.count());
34
+ yield queue.whenCurrentJobsFinished();
35
+ });
36
+ }
37
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../../../../tests/core/utilities/utils/queue.ts"],"names":[],"mappings":";;;;;;;;;;;AAIA,sCAcC;AAED,0CAMC;AAzBD,mDAAuD;AACvD,8DAAsD;AAEtD,SAAsB,aAAa;;;QACjC,MAAM,KAAK,GAAG,MAAM,IAAA,mCAAc,EAChC,IAAI,iCAAgB,CAAC,OAAO,CAAC;aAC1B,gBAAgB,CAAC,IAAI,CAAC;aACtB,gBAAgB,CACf,qBAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CACjE,CACJ,CAAA;QAED,MAAM,IAAI,GAAG,MAAA,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,0CAAE,IAAI,CAAA;QACxD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;QACzC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;IACpD,CAAC;CAAA;AAED,SAAsB,eAAe,CAAC,KAAY;;QAChD,GAAG,CAAC;YACF,MAAM,KAAK,CAAC,uBAAuB,EAAE,CAAA;QACvC,CAAC,QAAQ,MAAM,KAAK,CAAC,KAAK,EAAE,EAAC;QAE7B,MAAM,KAAK,CAAC,uBAAuB,EAAE,CAAA;IACvC,CAAC;CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@budibase/backend-core",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Budibase backend core libraries used in server and worker",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -23,8 +23,8 @@
23
23
  "dependencies": {
24
24
  "@budibase/nano": "10.1.5",
25
25
  "@budibase/pouchdb-replication-stream": "1.2.11",
26
- "@budibase/shared-core": "3.2.0",
27
- "@budibase/types": "3.2.0",
26
+ "@budibase/shared-core": "3.2.1",
27
+ "@budibase/types": "3.2.1",
28
28
  "aws-cloudfront-sign": "3.0.2",
29
29
  "aws-sdk": "2.1030.0",
30
30
  "bcrypt": "5.1.0",
@@ -95,5 +95,5 @@
95
95
  }
96
96
  }
97
97
  },
98
- "gitHead": "03c8ffc9fe27435014a76bb4becd81278ad1ed9c"
98
+ "gitHead": "46f5cd0a5d1c053ce787de66825dce0c03d5e559"
99
99
  }
@@ -1,7 +1,12 @@
1
1
  import tk from "timekeeper"
2
2
 
3
3
  import _ from "lodash"
4
- import { DBTestConfiguration, generator, structures } from "../../../tests"
4
+ import {
5
+ DBTestConfiguration,
6
+ generator,
7
+ structures,
8
+ utils,
9
+ } from "../../../tests"
5
10
  import { getDB } from "../../db"
6
11
 
7
12
  import {
@@ -10,15 +15,14 @@ import {
10
15
  init,
11
16
  } from "../docWritethrough"
12
17
 
13
- import InMemoryQueue from "../../queue/inMemoryQueue"
14
-
15
18
  const initialTime = Date.now()
16
19
 
17
20
  async function waitForQueueCompletion() {
18
- const queue: InMemoryQueue = DocWritethroughProcessor.queue as never
19
- await queue.waitForCompletion()
21
+ await utils.queue.processMessages(DocWritethroughProcessor.queue)
20
22
  }
21
23
 
24
+ beforeAll(() => utils.queue.useRealQueues())
25
+
22
26
  describe("docWritethrough", () => {
23
27
  beforeAll(() => {
24
28
  init()
@@ -67,7 +71,7 @@ describe("docWritethrough", () => {
67
71
  const patch3 = generatePatchObject(3)
68
72
  await docWritethrough.patch(patch3)
69
73
 
70
- expect(await db.get(documentId)).toEqual({
74
+ expect(await db.tryGet(documentId)).toEqual({
71
75
  _id: documentId,
72
76
  ...patch1,
73
77
  ...patch2,
@@ -92,7 +96,7 @@ describe("docWritethrough", () => {
92
96
 
93
97
  await waitForQueueCompletion()
94
98
 
95
- expect(await db.get(documentId)).toEqual(
99
+ expect(await db.tryGet(documentId)).toEqual(
96
100
  expect.objectContaining({
97
101
  _id: documentId,
98
102
  ...patch1,
@@ -117,7 +121,7 @@ describe("docWritethrough", () => {
117
121
  await waitForQueueCompletion()
118
122
 
119
123
  expect(date1).not.toEqual(date2)
120
- expect(await db.get(documentId)).toEqual(
124
+ expect(await db.tryGet(documentId)).toEqual(
121
125
  expect.objectContaining({
122
126
  createdAt: date1.toISOString(),
123
127
  updatedAt: date2.toISOString(),
@@ -135,7 +139,7 @@ describe("docWritethrough", () => {
135
139
  await docWritethrough.patch(patch2)
136
140
 
137
141
  const keyToOverride = _.sample(Object.keys(patch1))!
138
- expect(await db.get(documentId)).toEqual(
142
+ expect(await db.tryGet(documentId)).toEqual(
139
143
  expect.objectContaining({
140
144
  [keyToOverride]: patch1[keyToOverride],
141
145
  })
@@ -150,7 +154,7 @@ describe("docWritethrough", () => {
150
154
  await docWritethrough.patch(patch3)
151
155
  await waitForQueueCompletion()
152
156
 
153
- expect(await db.get(documentId)).toEqual(
157
+ expect(await db.tryGet(documentId)).toEqual(
154
158
  expect.objectContaining({
155
159
  ...patch1,
156
160
  ...patch2,
@@ -180,14 +184,14 @@ describe("docWritethrough", () => {
180
184
  await secondDocWritethrough.patch(doc2Patch2)
181
185
  await waitForQueueCompletion()
182
186
 
183
- expect(await db.get(docWritethrough.docId)).toEqual(
187
+ expect(await db.tryGet(docWritethrough.docId)).toEqual(
184
188
  expect.objectContaining({
185
189
  ...doc1Patch,
186
190
  ...doc1Patch2,
187
191
  })
188
192
  )
189
193
 
190
- expect(await db.get(secondDocWritethrough.docId)).toEqual(
194
+ expect(await db.tryGet(secondDocWritethrough.docId)).toEqual(
191
195
  expect.objectContaining({
192
196
  ...doc2Patch,
193
197
  ...doc2Patch2,
@@ -203,7 +207,7 @@ describe("docWritethrough", () => {
203
207
  await docWritethrough.patch(initialPatch)
204
208
  await waitForQueueCompletion()
205
209
 
206
- expect(await db.get(documentId)).toEqual(
210
+ expect(await db.tryGet(documentId)).toEqual(
207
211
  expect.objectContaining(initialPatch)
208
212
  )
209
213
 
@@ -214,10 +218,10 @@ describe("docWritethrough", () => {
214
218
  await docWritethrough.patch(extraPatch)
215
219
  await waitForQueueCompletion()
216
220
 
217
- expect(await db.get(documentId)).toEqual(
221
+ expect(await db.tryGet(documentId)).toEqual(
218
222
  expect.objectContaining(extraPatch)
219
223
  )
220
- expect(await db.get(documentId)).not.toEqual(
224
+ expect(await db.tryGet(documentId)).not.toEqual(
221
225
  expect.objectContaining(initialPatch)
222
226
  )
223
227
  })
@@ -242,7 +246,7 @@ describe("docWritethrough", () => {
242
246
  expect(queueMessageSpy).toHaveBeenCalledTimes(5)
243
247
 
244
248
  await waitForQueueCompletion()
245
- expect(await db.get(documentId)).toEqual(
249
+ expect(await db.tryGet(documentId)).toEqual(
246
250
  expect.objectContaining(patches)
247
251
  )
248
252
 
@@ -250,7 +254,7 @@ describe("docWritethrough", () => {
250
254
  expect(queueMessageSpy).toHaveBeenCalledTimes(45)
251
255
 
252
256
  await waitForQueueCompletion()
253
- expect(await db.get(documentId)).toEqual(
257
+ expect(await db.tryGet(documentId)).toEqual(
254
258
  expect.objectContaining(patches)
255
259
  )
256
260
 
@@ -258,20 +262,18 @@ describe("docWritethrough", () => {
258
262
  expect(queueMessageSpy).toHaveBeenCalledTimes(55)
259
263
 
260
264
  await waitForQueueCompletion()
261
- expect(await db.get(documentId)).toEqual(
265
+ expect(await db.tryGet(documentId)).toEqual(
262
266
  expect.objectContaining(patches)
263
267
  )
264
268
  })
265
269
  })
266
270
 
267
- // This is not yet supported
268
- // eslint-disable-next-line jest/no-disabled-tests
269
- it.skip("patches will execute in order", async () => {
271
+ it("patches will execute in order", async () => {
270
272
  let incrementalValue = 0
271
273
  const keyToOverride = generator.word()
272
274
  async function incrementalPatches(count: number) {
273
275
  for (let i = 0; i < count; i++) {
274
- await docWritethrough.patch({ [keyToOverride]: incrementalValue++ })
276
+ await docWritethrough.patch({ [keyToOverride]: ++incrementalValue })
275
277
  }
276
278
  }
277
279
 
@@ -279,13 +281,13 @@ describe("docWritethrough", () => {
279
281
  await incrementalPatches(5)
280
282
 
281
283
  await waitForQueueCompletion()
282
- expect(await db.get(documentId)).toEqual(
284
+ expect(await db.tryGet(documentId)).toEqual(
283
285
  expect.objectContaining({ [keyToOverride]: 5 })
284
286
  )
285
287
 
286
288
  await incrementalPatches(40)
287
289
  await waitForQueueCompletion()
288
- expect(await db.get(documentId)).toEqual(
290
+ expect(await db.tryGet(documentId)).toEqual(
289
291
  expect.objectContaining({ [keyToOverride]: 45 })
290
292
  )
291
293
  })
@@ -1,5 +1,5 @@
1
1
  import events from "events"
2
- import { newid, timeout } from "../utils"
2
+ import { newid } from "../utils"
3
3
  import { Queue, QueueOptions, JobOptions } from "./queue"
4
4
 
5
5
  interface JobMessage {
@@ -141,7 +141,7 @@ class InMemoryQueue implements Partial<Queue> {
141
141
  } else {
142
142
  pushMessage()
143
143
  }
144
- return {} as any
144
+ return { id: jobId } as any
145
145
  }
146
146
 
147
147
  /**
@@ -184,16 +184,6 @@ class InMemoryQueue implements Partial<Queue> {
184
184
  // do nothing
185
185
  return this as any
186
186
  }
187
-
188
- async waitForCompletion() {
189
- do {
190
- await timeout(50)
191
- } while (this.hasRunningJobs())
192
- }
193
-
194
- hasRunningJobs() {
195
- return this._addCount > this._runCount
196
- }
197
187
  }
198
188
 
199
189
  export default InMemoryQueue
@@ -15,7 +15,7 @@ const QUEUE_LOCK_MS = Duration.fromMinutes(5).toMs()
15
15
  const QUEUE_LOCK_RENEW_INTERNAL_MS = Duration.fromSeconds(30).toMs()
16
16
  // cleanup the queue every 60 seconds
17
17
  const CLEANUP_PERIOD_MS = Duration.fromSeconds(60).toMs()
18
- let QUEUES: BullQueue.Queue[] | InMemoryQueue[] = []
18
+ let QUEUES: BullQueue.Queue[] = []
19
19
  let cleanupInterval: NodeJS.Timeout
20
20
 
21
21
  async function cleanup() {
@@ -45,11 +45,18 @@ export function createQueue<T>(
45
45
  if (opts.jobOptions) {
46
46
  queueConfig.defaultJobOptions = opts.jobOptions
47
47
  }
48
- let queue: any
48
+ let queue: BullQueue.Queue<T>
49
49
  if (!env.isTest()) {
50
50
  queue = new BullQueue(jobQueue, queueConfig)
51
+ } else if (
52
+ process.env.BULL_TEST_REDIS_PORT &&
53
+ !isNaN(+process.env.BULL_TEST_REDIS_PORT)
54
+ ) {
55
+ queue = new BullQueue(jobQueue, {
56
+ redis: { host: "localhost", port: +process.env.BULL_TEST_REDIS_PORT },
57
+ })
51
58
  } else {
52
- queue = new InMemoryQueue(jobQueue, queueConfig)
59
+ queue = new InMemoryQueue(jobQueue, queueConfig) as any
53
60
  }
54
61
  addListeners(queue, jobQueue, opts?.removeStalledCb)
55
62
  QUEUES.push(queue)
@@ -4,3 +4,4 @@ export { generator } from "./structures"
4
4
  export * as testContainerUtils from "./testContainerUtils"
5
5
  export * as utils from "./utils"
6
6
  export * from "./jestUtils"
7
+ export * as queue from "./queue"
@@ -0,0 +1,9 @@
1
+ import { Queue } from "bull"
2
+
3
+ export async function processMessages(queue: Queue) {
4
+ do {
5
+ await queue.whenCurrentJobsFinished()
6
+ } while (await queue.count())
7
+
8
+ await queue.whenCurrentJobsFinished()
9
+ }
@@ -1,4 +1,6 @@
1
1
  import { execSync } from "child_process"
2
+ import { cloneDeep } from "lodash"
3
+ import { GenericContainer, StartedTestContainer } from "testcontainers"
2
4
 
3
5
  const IPV4_PORT_REGEX = new RegExp(`0\\.0\\.0\\.0:(\\d+)->(\\d+)/tcp`, "g")
4
6
 
@@ -106,3 +108,58 @@ export function setupEnv(...envs: any[]) {
106
108
  }
107
109
  }
108
110
  }
111
+
112
+ export async function startContainer(container: GenericContainer) {
113
+ const imageName = (container as any).imageName.string as string
114
+ let key: string = imageName
115
+ if (imageName.includes("@sha256")) {
116
+ key = imageName.split("@")[0]
117
+ }
118
+ key = key.replace(/\//g, "-").replace(/:/g, "-")
119
+
120
+ container = container
121
+ .withReuse()
122
+ .withLabels({ "com.budibase": "true" })
123
+ .withName(`${key}_testcontainer`)
124
+
125
+ let startedContainer: StartedTestContainer | undefined = undefined
126
+ let lastError = undefined
127
+ for (let i = 0; i < 10; i++) {
128
+ try {
129
+ // container.start() is not an idempotent operation, calling `start`
130
+ // modifies the internal state of a GenericContainer instance such that
131
+ // the hash it uses to determine reuse changes. We need to clone the
132
+ // container before calling start to ensure that we're using the same
133
+ // reuse hash every time.
134
+ const containerCopy = cloneDeep(container)
135
+ startedContainer = await containerCopy.start()
136
+ lastError = undefined
137
+ break
138
+ } catch (e: any) {
139
+ lastError = e
140
+ await new Promise(resolve => setTimeout(resolve, 1000))
141
+ }
142
+ }
143
+
144
+ if (!startedContainer) {
145
+ if (lastError) {
146
+ throw lastError
147
+ }
148
+ throw new Error(`failed to start container: ${imageName}`)
149
+ }
150
+
151
+ const info = getContainerById(startedContainer.getId())
152
+ if (!info) {
153
+ throw new Error("Container not found")
154
+ }
155
+
156
+ // Some Docker runtimes, when you expose a port, will bind it to both
157
+ // 127.0.0.1 and ::1, so ipv4 and ipv6. The port spaces of ipv4 and ipv6
158
+ // addresses are not shared, and testcontainers will sometimes give you back
159
+ // the ipv6 port. There's no way to know that this has happened, and if you
160
+ // try to then connect to `localhost:port` you may attempt to bind to the v4
161
+ // address which could be unbound or even an entirely different container. For
162
+ // that reason, we don't use testcontainers' `getExposedPort` function,
163
+ // preferring instead our own method that guaranteed v4 ports.
164
+ return getExposedV4Ports(info)
165
+ }
@@ -1 +1,2 @@
1
1
  export * as time from "./time"
2
+ export * as queue from "./queue"
@@ -0,0 +1,27 @@
1
+ import { Queue } from "bull"
2
+ import { GenericContainer, Wait } from "testcontainers"
3
+ import { startContainer } from "../testContainerUtils"
4
+
5
+ export async function useRealQueues() {
6
+ const ports = await startContainer(
7
+ new GenericContainer("redis")
8
+ .withExposedPorts(6379)
9
+ .withWaitStrategy(
10
+ Wait.forSuccessfulCommand(`redis-cli`).withStartupTimeout(10000)
11
+ )
12
+ )
13
+
14
+ const port = ports.find(x => x.container === 6379)?.host
15
+ if (!port) {
16
+ throw new Error("Redis port not found")
17
+ }
18
+ process.env.BULL_TEST_REDIS_PORT = port.toString()
19
+ }
20
+
21
+ export async function processMessages(queue: Queue) {
22
+ do {
23
+ await queue.whenCurrentJobsFinished()
24
+ } while (await queue.count())
25
+
26
+ await queue.whenCurrentJobsFinished()
27
+ }