Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Commit a366c1f

Browse files
committed
Add unit test for config format migration
1 parent 74099d4 commit a366c1f

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

nodecg-io-core/extension/__tests__/mocks.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ObjectMap, ServiceInstance } from "../service";
1+
import { ObjectMap, ServiceInstance, Service } from "../service";
22
import type { NodeCG, ReplicantOptions, Replicant, Logger } from "nodecg-types/types/server";
33
import { EventEmitter } from "events";
44

@@ -144,6 +144,24 @@ export const testService = {
144144
},
145145
};
146146

147+
export const websocketServerService: Service<{ port: number }, void> = {
148+
serviceType: "websocket-server",
149+
validateConfig: jest.fn(),
150+
createClient: jest.fn(),
151+
stopClient: jest.fn(),
152+
reCreateClientToRemoveHandlers: false,
153+
requiresNoConfig: false,
154+
schema: {
155+
$schema: "http://json-schema.org/draft-07/schema#",
156+
type: "object",
157+
properties: {
158+
port: {
159+
type: "integer",
160+
},
161+
},
162+
},
163+
};
164+
147165
export const testServiceInstance: ServiceInstance<string, () => string> = {
148166
serviceType: testService.serviceType,
149167
config: "hello world",

nodecg-io-core/extension/__tests__/persistenceManager.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@ import {
55
decryptData,
66
deriveEncryptionKey,
77
EncryptedData,
8+
getEncryptionSalt,
89
PersistenceManager,
910
PersistentData,
1011
} from "../persistenceManager";
1112
import { ServiceManager } from "../serviceManager";
1213
import { ServiceProvider } from "../serviceProvider";
1314
import { emptySuccess, error } from "../utils/result";
14-
import { MockNodeCG, testBundle, testInstance, testService, testServiceInstance } from "./mocks";
15+
import {
16+
MockNodeCG,
17+
testBundle,
18+
testInstance,
19+
testService,
20+
testServiceInstance,
21+
websocketServerService,
22+
} from "./mocks";
1523

1624
describe("PersistenceManager", () => {
1725
const validPassword = "myPassword";
@@ -23,6 +31,7 @@ describe("PersistenceManager", () => {
2331
const nodecg = new MockNodeCG();
2432
const serviceManager = new ServiceManager(nodecg);
2533
serviceManager.registerService(testService);
34+
serviceManager.registerService(websocketServerService);
2635

2736
let bundleManager: BundleManager;
2837
let instanceManager: InstanceManager;
@@ -262,6 +271,54 @@ describe("PersistenceManager", () => {
262271
expect(deps?.[0]).toBeDefined();
263272
expect(deps?.[0]?.serviceInstance).toBeUndefined();
264273
});
274+
275+
// Config migration
276+
277+
test("should be able to migrate nodecg-io <= 0.2 config to a newer nodecg-io >= 0.3 config", async () => {
278+
// Old nodecg-io 0.2 config with the following values:
279+
// password: 654321
280+
// services:
281+
// ws -> websocket-server
282+
// port: 5678
283+
// bundles:
284+
// ws-server-test:
285+
// websocket-server -> ws
286+
const oldConfig: EncryptedData = {
287+
cipherText:
288+
"U2FsdGVkX19/ECpN7V/FUE4WQ3Fp5mb/0y06HHG6TVw7oRdQfMygbnfP2VtgJ7MVx/Uw7U5wI7jlwSNHN/3eG0rY0Du2E5jJbHr3OHl5OfgsZKWbGVoEzuCtEsLjSz1FeEf4C2VIvjWeJWTKBmSm+DVitNRwwM6Ex+f97gI0HbWjU9qVhBsw05RY9vA4/XpsucRdEh5Q6RIDnVn3Gj75OlB7IlsygCv2IzxnGqx4vr3k8J4kQo8DBhyOdxQtYCkHSpuM0d3cBOMAgySZWcw2EU5PN7F6wMmeR5Zko10LhNuMntSD+Zw6yZFeFPVDRM4OhVv8146zZX5+w3XJX2KZjQ==",
289+
};
290+
encryptedDataReplicant.value = oldConfig;
291+
bundleManager.registerServiceDependency("ws-server-test", websocketServerService);
292+
293+
// Invalid keys should also error with olds configs
294+
const invalidResult = await persistenceManager.load(invalidEncryptionKey);
295+
expect(invalidResult.failed).toBe(true);
296+
297+
// Loading should just work and migrate the configuration
298+
const password = "654321";
299+
const salt = await getEncryptionSalt(oldConfig, password);
300+
const encryptionKey = await deriveEncryptionKey(password, salt);
301+
const correctPasswordResult = await persistenceManager.load(encryptionKey);
302+
expect(correctPasswordResult.failed).toBe(false);
303+
304+
// Config has been migrated: salt and iv are only present in nodecg-io >=0.3 configs
305+
expect(oldConfig.salt).toBeDefined();
306+
expect(oldConfig.iv).toBeDefined();
307+
308+
// Check instances and bundles for correct data
309+
expect(instanceManager.getServiceInstance("ws")).toBeDefined();
310+
expect(instanceManager.getServiceInstance("ws")?.config).toEqual({
311+
port: 5678,
312+
});
313+
314+
expect(bundleManager.getBundleDependencies()["ws-server-test"]).toEqual([
315+
{
316+
serviceType: "websocket-server",
317+
serviceInstance: "ws",
318+
provider: new ServiceProvider(),
319+
},
320+
]);
321+
});
265322
});
266323

267324
describe("save", () => {

0 commit comments

Comments
 (0)