You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/test/session/unit/onion/GuardNodes_test.js

133 lines
23 KiB
JavaScript

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
var import_chai = __toESM(require("chai"));
var sinon = __toESM(require("sinon"));
var import_mocha = require("mocha");
var import_test_utils = require("../../../test-utils");
var import_snode_api = require("../../../../session/apis/snode_api");
var Data = __toESM(require("../../../../data/data"));
var import_chai_as_promised = __toESM(require("chai-as-promised"));
var OnionPaths = __toESM(require("../../../../session/onions/onionPath"));
var import_utils = require("../../../test-utils/utils");
var import_seed_node_api = require("../../../../session/apis/seed_node_api");
import_chai.default.use(import_chai_as_promised.default);
import_chai.default.should();
const { expect } = import_chai.default;
const guard1ed = "e3ec6fcc79e64c2af6a48a9865d4bf4b739ec7708d75f35acc3d478f9161534e";
const guard2ed = "e3ec6fcc79e64c2af6a48a9865d4bf4b739ec7708d75f35acc3d478f91615349";
const guard3ed = "e3ec6fcc79e64c2af6a48a9865d4bf4b739ec7708d75f35acc3d478f9161534a";
const fakeSnodePool = [
...(0, import_utils.generateFakeSnodes)(12),
(0, import_utils.generateFakeSnodeWithEdKey)(guard1ed),
(0, import_utils.generateFakeSnodeWithEdKey)(guard2ed),
(0, import_utils.generateFakeSnodeWithEdKey)(guard3ed),
...(0, import_utils.generateFakeSnodes)(3)
];
(0, import_mocha.describe)("GuardNodes", () => {
const sandbox = sinon.createSandbox();
let getSnodePoolFromDBOrFetchFromSeed;
let fetchFromSeedWithRetriesAndWriteToDb;
(0, import_mocha.describe)("selectGuardNodes", () => {
beforeEach(() => {
OnionPaths.clearTestOnionPath();
import_test_utils.TestUtils.stubWindowLog();
import_test_utils.TestUtils.stubWindow("getGlobalOnlineStatus", () => true);
import_snode_api.Onions.resetSnodeFailureCount();
OnionPaths.resetPathFailureCount();
import_snode_api.SnodePool.TEST_resetState();
});
afterEach(() => {
import_test_utils.TestUtils.restoreStubs();
sandbox.restore();
});
it("does not fetch from seed if we got 12 or more snodes in the db", async () => {
sandbox.stub(Data, "getSnodePoolFromDb").resolves(fakeSnodePool);
getSnodePoolFromDBOrFetchFromSeed = sandbox.stub(import_snode_api.SnodePool, "getSnodePoolFromDBOrFetchFromSeed").callThrough();
fetchFromSeedWithRetriesAndWriteToDb = sandbox.stub(import_snode_api.SnodePool, "TEST_fetchFromSeedWithRetriesAndWriteToDb").resolves();
const testGuardNode = sandbox.stub(OnionPaths, "TEST_testGuardNode").resolves(true);
sandbox.stub(Data, "updateGuardNodes").resolves();
const fetchedGuardNodes = await OnionPaths.selectGuardNodes();
expect(getSnodePoolFromDBOrFetchFromSeed.callCount, "getSnodePoolFromDBOrFetchFromSeed should have been called").to.be.eq(1);
expect(fetchFromSeedWithRetriesAndWriteToDb.callCount, "fetchFromSeedWithRetriesAndWriteToDb should not have been called").to.be.eq(0);
expect(testGuardNode.callCount, "firstGuardNode should have been called three times").to.be.eq(3);
const firstGuardNode = testGuardNode.firstCall.args[0];
const secondGuardNode = testGuardNode.secondCall.args[0];
const thirdGuardNode = testGuardNode.thirdCall.args[0];
expect(fetchedGuardNodes).to.deep.equal([firstGuardNode, secondGuardNode, thirdGuardNode]);
});
it("throws an error if we got enough snodes in the db but none test passes", async () => {
sandbox.stub(Data, "getSnodePoolFromDb").resolves(fakeSnodePool);
getSnodePoolFromDBOrFetchFromSeed = sandbox.stub(import_snode_api.SnodePool, "getSnodePoolFromDBOrFetchFromSeed").callThrough();
fetchFromSeedWithRetriesAndWriteToDb = sandbox.stub(import_snode_api.SnodePool, "TEST_fetchFromSeedWithRetriesAndWriteToDb").resolves();
const testGuardNode = sandbox.stub(OnionPaths, "TEST_testGuardNode").resolves(false);
sandbox.stub(Data, "updateGuardNodes").resolves();
let throwedError;
try {
await OnionPaths.selectGuardNodes();
} catch (e) {
throwedError = e.message;
}
expect(getSnodePoolFromDBOrFetchFromSeed.callCount, "getSnodePoolFromDBOrFetchFromSeed should have been called").to.be.eq(1);
expect(fetchFromSeedWithRetriesAndWriteToDb.callCount, "fetchFromSeedWithRetriesAndWriteToDb should not have been called").to.be.eq(0);
expect(testGuardNode.callCount, "firstGuardNode should have been called three times").to.be.eq(18);
expect(throwedError).to.be.equal("selectGuardNodes stopping after attempts: 6");
});
it("throws an error if we have to fetch from seed, fetch from seed enough snode but we still fail", async () => {
const invalidSndodePool = fakeSnodePool.slice(0, 11);
sandbox.stub(Data, "getSnodePoolFromDb").resolves(invalidSndodePool);
import_test_utils.TestUtils.stubWindow("getSeedNodeList", () => [{ url: "whatever" }]);
getSnodePoolFromDBOrFetchFromSeed = sandbox.stub(import_snode_api.SnodePool, "getSnodePoolFromDBOrFetchFromSeed").callThrough();
fetchFromSeedWithRetriesAndWriteToDb = sandbox.stub(import_seed_node_api.SeedNodeAPI, "fetchSnodePoolFromSeedNodeWithRetries").resolves(fakeSnodePool);
sandbox.stub(Data, "updateGuardNodes").resolves();
let throwedError;
try {
await OnionPaths.selectGuardNodes();
} catch (e) {
throwedError = e.message;
}
expect(throwedError).to.be.equal("selectGuardNodes stopping after attempts: 6");
});
it("returns valid guardnode if we have to fetch from seed, fetch from seed enough snodes but guard node tests passes", async () => {
const invalidSndodePool = fakeSnodePool.slice(0, 11);
sandbox.stub(Data, "getSnodePoolFromDb").resolves(invalidSndodePool);
import_test_utils.TestUtils.stubWindow("getSeedNodeList", () => [{ url: "whatever" }]);
const testGuardNode = sandbox.stub(OnionPaths, "TEST_testGuardNode").resolves(true);
getSnodePoolFromDBOrFetchFromSeed = sandbox.stub(import_snode_api.SnodePool, "getSnodePoolFromDBOrFetchFromSeed").callThrough();
fetchFromSeedWithRetriesAndWriteToDb = sandbox.stub(import_seed_node_api.SeedNodeAPI, "fetchSnodePoolFromSeedNodeWithRetries").resolves(fakeSnodePool);
sandbox.stub(Data, "updateGuardNodes").resolves();
const guardNodes = await OnionPaths.selectGuardNodes();
expect(guardNodes.length).to.be.equal(3);
expect(testGuardNode.callCount).to.be.equal(3);
});
it("throws if we have to fetch from seed, fetch from seed but not have enough fetched snodes", async () => {
const invalidSndodePool = fakeSnodePool.slice(0, 11);
sandbox.stub(Data, "getSnodePoolFromDb").resolves(invalidSndodePool);
import_test_utils.TestUtils.stubWindow("getSeedNodeList", () => [{ url: "whatever" }]);
getSnodePoolFromDBOrFetchFromSeed = sandbox.stub(import_snode_api.SnodePool, "getSnodePoolFromDBOrFetchFromSeed").callThrough();
fetchFromSeedWithRetriesAndWriteToDb = sandbox.stub(import_seed_node_api.SeedNodeAPI, "fetchSnodePoolFromSeedNodeWithRetries").resolves(invalidSndodePool);
sandbox.stub(Data, "updateGuardNodes").resolves();
let throwedError;
try {
await OnionPaths.selectGuardNodes();
} catch (e) {
throwedError = e.message;
}
expect(throwedError).to.be.equal("Could not select guard nodes. Not enough nodes in the pool: 11");
});
});
});
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vdHMvdGVzdC9zZXNzaW9uL3VuaXQvb25pb24vR3VhcmROb2Rlc190ZXN0LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvLyB0c2xpbnQ6ZGlzYWJsZTogbm8taW1wbGljaXQtZGVwZW5kZW5jaWVzIG1heC1mdW5jLWJvZHktbGVuZ3RoIG5vLXVudXNlZC1leHByZXNzaW9uXG5cbmltcG9ydCBjaGFpIGZyb20gJ2NoYWknO1xuaW1wb3J0ICogYXMgc2lub24gZnJvbSAnc2lub24nO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IGRlc2NyaWJlIH0gZnJvbSAnbW9jaGEnO1xuXG5pbXBvcnQgeyBUZXN0VXRpbHMgfSBmcm9tICcuLi8uLi8uLi90ZXN0LXV0aWxzJztcbmltcG9ydCB7IE9uaW9ucywgU25vZGVQb29sIH0gZnJvbSAnLi4vLi4vLi4vLi4vc2Vzc2lvbi9hcGlzL3Nub2RlX2FwaSc7XG5pbXBvcnQgKiBhcyBEYXRhIGZyb20gJy4uLy4uLy4uLy4uL2RhdGEvZGF0YSc7XG5cbmltcG9ydCBjaGFpQXNQcm9taXNlZCBmcm9tICdjaGFpLWFzLXByb21pc2VkJztcbmltcG9ydCAqIGFzIE9uaW9uUGF0aHMgZnJvbSAnLi4vLi4vLi4vLi4vc2Vzc2lvbi9vbmlvbnMvb25pb25QYXRoJztcbmltcG9ydCB7IGdlbmVyYXRlRmFrZVNub2RlcywgZ2VuZXJhdGVGYWtlU25vZGVXaXRoRWRLZXkgfSBmcm9tICcuLi8uLi8uLi90ZXN0LXV0aWxzL3V0aWxzJztcbmltcG9ydCB7IFNlZWROb2RlQVBJIH0gZnJvbSAnLi4vLi4vLi4vLi4vc2Vzc2lvbi9hcGlzL3NlZWRfbm9kZV9hcGknO1xuY2hhaS51c2UoY2hhaUFzUHJvbWlzZWQgYXMgYW55KTtcbmNoYWkuc2hvdWxkKCk7XG5cbmNvbnN0IHsgZXhwZWN0IH0gPSBjaGFpO1xuXG5jb25zdCBndWFyZDFlZCA9ICdlM2VjNmZjYzc5ZTY0YzJhZjZhNDhhOTg2NWQ0YmY0YjczOWVjNzcwOGQ3NWYzNWFjYzNkNDc4ZjkxNjE1MzRlJztcbmNvbnN0IGd1YXJkMmVkID0gJ2UzZWM2ZmNjNzllNjRjMmFmNmE0OGE5ODY1ZDRiZjRiNzM5ZWM3NzA4ZDc1ZjM1YWNjM2Q0NzhmOTE2MTUzNDknO1xuY29uc3QgZ3VhcmQzZWQgPSAnZTNlYzZmY2M3OWU2NGMyYWY2YTQ4YTk4NjVkNGJmNGI3MzllYzc3MDhkNzVmMzVhY2MzZDQ3OGY5MTYxNTM0YSc7XG5cbmNvbnN0IGZha2VTbm9kZVBvb2w6IEFycmF5PERhdGEuU25vZGU+ID0gW1xuICAuLi5nZW5lcmF0ZUZha2VTbm9kZXMoMTIpLFxuICBnZW5lcmF0ZUZha2VTbm9kZVdpdGhFZEtleShndWFyZDFlZCksXG4gIGdlbmVyYXRlRmFrZVNub2RlV2l0aEVkS2V5KGd1YXJkMmVkKSxcbiAgZ2VuZXJhdGVGYWtlU25vZGVXaXRoRWRLZXkoZ3VhcmQzZWQpLFxuICAuLi5nZW5lcmF0ZUZha2VTbm9kZXMoMyksXG5dO1xuXG4vLyB0c2xpbnQ6ZGlzYWJsZTogdmFyaWFibGUtbmFtZVxuXG4vLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6IG1heC1mdW5jLWJvZHktbGVuZ3RoXG5kZXNjcmliZSgnR3VhcmROb2RlcycsICgpID0+IHtcbiAgLy8gSW5pdGlhbGl6ZSBuZXcgc3R1YmJlZCBjYWNoZVxuICBjb25zdCBzYW5kYm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuICBsZXQgZ2V0U25vZGVQb29sRnJvbURCT3JGZXRjaEZyb21TZWVkOiBzaW5vbi5TaW5vblN0dWI7XG4gIGxldCBmZXRjaEZyb21TZWVkV2l0aFJldHJpZXNBbmRXcml0ZVRvRGI6IHNpbm9uLlNpbm9uU3R1YjtcbiAgZGVzY3JpYmUoJ3NlbGVjdEd1YXJkTm9kZXMnLCAoKSA9PiB7XG4gICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICBPbmlvblBhdGhzLmNsZWFyVGVzdE9uaW9uUGF0aCgpO1xuXG4gICAgICBUZXN0VXRpbHMuc3R1YldpbmRvd0xvZygpO1xuICAgICAgVGVzdFV0aWxzLnN0dWJXaW5kb3coJ2dldEdsb2JhbE9ubGluZVN0YXR1cycsICgpID0+IHRydWUpO1xuXG4gICAgICBPbmlvbnMucmVzZXRTbm9kZUZhaWx1cmVDb3VudCgpO1xuICAgICAgT25pb25QYXRocy5yZXNldFBhdGhGYWlsdXJlQ291bnQoKTtcbiAgICAgIFNub2RlUG9vbC5URVNUX3Jlc2V0U3RhdGUoKTtcbiAgICB9KTtcblxuICAgIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgICBUZXN0VXRpbHMucmVzdG9yZVN0dWJzKCk7XG4gICAgICBzYW5kYm94LnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdkb2VzIG5vdCBmZXRjaCBmcm9tIHNlZWQgaWYgd2UgZ290IDEyIG9yIG1vcmUgc25vZGVzIGluIHRoZSBkYicsIGFzeW5jICgpID0+IHtcbiAgICAgIHNhbmRib3guc3R1YihEYXRhLCAnZ2V0U25vZGVQb29sRnJvbURiJykucmVzb2x2ZXMoZmFrZVNub2RlUG9vbCk7XG5cbiAgICAgIGdldFNub2RlUG9vbEZyb21EQk9yRmV0Y2hGcm9tU2VlZCA9IHNhbmRib3hcbiAgICAgICAgLnN0dWIoU25vZGVQb29sLCAnZ2V0U25vZGVQb29sRnJvbURCT3JGZXRjaEZyb21TZWVkJylcbiAgICAgICAgLmNhbGxUaHJvdWdoKCk7XG4gICAgICBmZXRjaEZyb21TZWVkV2l0aFJldHJpZXNBbmRXcml0ZVRvRGIgPSBzYW5kYm94XG4gICAgICAgIC5zdHViKFNub2RlUG9vbCwgJ1RFU1RfZmV0Y2hGcm9tU2VlZFdpdGhSZXRyaWVzQW5kV3JpdGVUb0RiJylcbiAgICAgICAgLnJlc29sdmVzKCk7XG4gICAgICBjb25zdCB0ZXN0R3VhcmROb2RlID0gc2FuZGJveC5zdHViKE9uaW9uUGF0aHMsICdURVNUX3Rlc3RHdWFyZE5vZGUnKS5yZXNvbHZlcyh0cnVlKTtcblxuICAgICAgc2FuZGJveC5zdHViKERhdGEsICd1cGRhdGVHdWFyZE5vZGVzJykucmVzb2x2ZXMoKTtcbiAgICAgIC8vIHJ1biB0aGUgY29tbWFuZFxuICAgICAgY29uc3QgZmV0Y2hlZEd1YXJkTm9kZXMgPSBhd2FpdCBPbmlvblBhdGhzLnNlbGVjdEd1YXJkTm9kZXMoKTtcblxuICAgICAgZXhwZWN0KFxuICAgICAgICBnZXRTbm9kZVBvb2xGcm9tREJPckZldGNoRnJvbVNlZWQuY2FsbENvdW50LFxuICAgICAgICAnZ2V0U25vZGVQb29sRnJvbURCT3JGZXRjaEZyb21TZWVkIHNob3VsZCBoYXZlIGJlZW4gY2FsbGVkJ1xuICAgICAgKS50by5iZS5lcSgxKTtcbiAgICAgIGV4cGVjdChcbiAgICAgICAgZmV0Y2hGcm9tU2VlZFdpdGhSZXRyaWVzQW5kV3JpdGVUb0RiLmNhbGxDb3VudCxcbiAgICAgICAgJ2ZldGNoRnJvbVNlZWRXaXRoUmV0cmllc0FuZFdyaXRlVG9EYiBzaG91bGQgbm90IGhhdmUgYmVlbiBjYWxsZWQnXG4gICAgICApLnRvLmJlLmVxKDApO1xuICAgICAgZXhwZWN0KFxuICAgICAgICB0ZXN0R3VhcmROb2RlLmNhbGxDb3VudCxcbiAgICAgICAgJ2ZpcnN0R3VhcmROb2RlIHNob3VsZCBoYXZlIGJlZW4gY2FsbGVkIHRocmVlIHRpbWVzJ1xuICAgICAgKS50by5iZS5lcSgzKTtcbiAgICAgIGNvbnN0IGZpcnN0R3VhcmROb2RlID0gdGVzdEd1YXJkTm9kZS5maXJzdENhbGwuYXJnc1swXTtcbiAgICAgIGNvbnN0IHNlY29uZEd1YXJkTm9kZSA9IHRlc3RHdWFyZE5vZGUuc2Vjb25kQ2FsbC5hcmdzWzBdO1xuICAgICAgY29uc3QgdGhpcmRHdWFyZE5vZGUgPSB0ZXN0R3VhcmROb2RlLnRoaXJkQ2FsbC5hcmdzWzBdO1xuICAgICAgZXhwZWN0KGZldGNoZWRHdWFyZE5vZGVzKS50by5kZWVwLmVxdWFsKFtmaXJzdEd1YXJkTm9kZSwgc2Vjb25kR3VhcmROb2RlLCB0aGlyZEd1YXJkTm9kZV0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Rocm93cyBhbiBlcnJvciBpZiB3ZSBnb3QgZW5vdWdoIHNub2RlcyBpbiB0aGUgZGIgYnV0IG5vbmUgdGVzdCBwYXNzZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgICBzYW5kYm94LnN0dWIoRGF0YSwgJ2dldFNub2RlUG9vbEZyb21EYicpLnJlc29sdmVzKGZha2VTbm9kZVBvb2wpO1xuXG4gICAgICBnZXRTbm9kZVBvb2xGcm9tREJPckZldGNoRnJvbVNlZWQgPSBzYW5kYm94XG4gICAgICAgIC5zdHViKFNub2RlUG9vbCwgJ2dldFNub2RlUG9vbEZyb21EQk9yRmV0Y2hGcm9tU2VlZCcpXG4gICAgICAgIC5jYWxsVGhyb3VnaCgpO1xuICAgICAgZmV0Y2hGcm9tU2VlZFdpdGhSZXRyaWVzQW5kV3JpdGVUb0RiID0gc2FuZGJveFxuICAgICAgICAuc3R1YihTbm9kZVBvb2wsICdURVNUX2ZldGNoRnJvbVNlZWRXaXRoUmV0cmllc0FuZFdyaXRlVG9EYicpXG4gICAgICAgIC5yZXNvbHZlcygpO1xuICAgICAgY29uc3QgdGVzdEd1YXJkTm9kZSA9IHNhbmRib3guc3R1YihPbmlvblBhdGhzLCAnVEVTVF90ZXN0R3VhcmROb2RlJykucmVzb2x2ZXMoZmFsc2UpO1xuXG4gICAgICBzYW5kYm94LnN0dWIoRGF0YSwgJ3VwZGF0ZUd1YXJkTm9kZXMnKS5yZXNvbHZlcygpO1xuICAgICAgLy8gcnVuIHRoZSBjb21tYW5kXG4gICAgICBsZXQgdGhyb3dlZEVycm9yOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBPbmlvblBhdGhzLnNlbGVjdEd1YXJkTm9kZXMoKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3dlZEVycm9yID0gZS5tZXNzYWdlO1xuICAgICAgfVxuXG4gICAgICBleHBlY3QoXG4gICAgICAgIGdldFNub2RlUG9vbEZyb21EQk9yRmV0Y2hGcm9tU2VlZC5jYWxsQ291bnQsXG4gICAgICAgICdnZXRTbm9kZVBvb2xGcm9tREJPckZldGNoRnJvbVNlZWQgc2hvdWxkIGhhdmUgYmVlbiBjYWxsZWQnXG4gICAgICApLnRvLmJlLmVxKDEpO1xuICAgICAgZXhwZWN0KFxuICAgICAgICBmZXRjaEZyb21TZWVkV2l0aFJldHJpZXNBbmRXcml0ZVRvRGIuY2FsbENvdW50LFxuICAgICAgICAnZmV0Y2hGcm9tU2VlZFdpdGhSZXRyaWVzQW5kV3JpdGVUb0RiIHNob3VsZCBub3QgaGF2ZSBiZWVuIGNhbGxlZCdcbiAgICAgICkudG8uYmUuZXEoMCk7XG4gICAgICBleHBlY3QoXG4gICAgICAgIHRlc3RHdWFyZE5vZGUuY2FsbENvdW50LFxuICAgICAgICAnZmlyc3RHdWFyZE5vZGUgc2hvdWxkIGhhdmUgYmVlbiBjYWxsZWQgdGhyZWUgdGltZXMnXG4gICAgICApLnRvLmJlLmVxKDE4KTtcbiAgICAgIGV4cGVjdCh0aHJvd2VkRXJyb3IpLnRvLmJlLmVxdWFsKCdzZWxlY3RHdWFyZE5vZGVzIHN0b3BwaW5nIGFmdGVyIGF0dGVtcHRzOiA2Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgndGhyb3dzIGFuIGVycm9yIGlmIHdlIGhhdmUgdG8gZmV0Y2ggZnJvbSBzZWVkLCBmZXRjaCBmcm9tIHNlZWQgZW5vdWdoIHNub2RlIGJ1dCB3ZSBzdGlsbCBmYWlsJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgaW52YWxpZFNuZG9kZVBvb2wgPSBmYWtlU25vZGVQb29sLnNsaWNlKDAsIDExKTtcbiAgICAgIHNhbmRib3guc3R1YihEYXRhLCAnZ2V0U25vZGVQb29sRnJvbURiJykucmVzb2x2ZXMoaW52YWxpZFNuZG9kZVBvb2wpO1xuICAgICAgVGVzdFV0aWxzLnN0dWJXaW5kb3coJ2dldFNlZWROb2RlTGlzdCcsICgpID0+IFt7IHVybDogJ3doYXRldmVyJyB9XSk7XG5cbiAgICAgIGdldFNub2RlUG9vbEZyb21EQk9yRmV0Y2hGcm9tU2VlZCA9IHNhbmRib3hcbiAgICAgICAgLnN0dWIoU25vZGVQb29sLCAnZ2V0U25vZGVQb29sRnJvbURCT3JGZXRjaEZyb21TZWVkJylcbiAgICAgICAgLmNhbGxUaHJvdWdoKCk7XG4gICAgICBmZXRjaEZyb21TZWVkV2l0aFJldHJpZXNBbmRXcml0ZVRvRGIgPSBzYW5kYm94XG4gICAgICAgIC5zdHViKFNlZWROb2RlQVBJLCAnZmV0Y2hTbm9kZVBvb2xGcm9tU2VlZE5vZGVXaXRoUmV0cmllcycpXG4gICAgICAgIC5yZXNvbHZlcyhmYWtlU25vZGVQb29sKTtcblxuICAgICAgc2FuZGJveC5zdHViKERhdGEsICd1cGRhdGVHdWFyZE5vZGVzJykucmVzb2x2ZXMoKTtcbiAgICAgIC8vIHJ1biB0aGUgY29tbWFuZFxuICAgICAgbGV0IHRocm93ZWRFcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgT25pb25QYXRocy5zZWxlY3RHdWFyZE5vZGVzKCk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93ZWRFcnJvciA9IGUubWVzc2FnZTtcbiAgICAgIH1cblxuICAgICAgZXhwZWN0KHRocm93ZWRFcnJvcikudG8uYmUuZXF1YWwoJ3NlbGVjdEd1YXJkTm9kZXMgc3RvcHBpbmcgYWZ0ZXIgYXR0ZW1wdHM6IDYnKTtcbiAgICB9KTtcblxuICAgIGl0KCdyZXR1cm5zIHZhbGlkIGd1YXJkbm9kZSBpZiB3ZSBoYXZlIHRvIGZldGNoIGZyb20gc2VlZCwgZmV0Y2ggZnJvbSBzZWVkIGVub3VnaCBzbm9kZXMgYnV0IGd1YXJkIG5vZGUgdGVzdHMgcGFzc2VzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgaW52YWxpZFNuZG9kZVBvb2wgPSBmYWtlU25vZGVQb29sLnNsaWNlKDAsIDExKTtcbiAgICAgIHNhbmRib3guc3R1YihEYXRhLCAnZ2V0U25vZGVQb29sRnJvbURiJykucmVzb2x2ZXMoaW52YWxpZFNuZG9kZVBvb2wpO1xuICAgICAgVGVzdFV0aWxzLnN0dWJXaW5kb3coJ2dldFNlZWROb2RlTGlzdCcsICgpID0+IFt7IHVybDogJ3doYXRldmVyJyB9XSk7XG4gICAgICBjb25zdCB0ZXN0R3VhcmROb2RlID0gc2FuZGJveC5zdHViKE9uaW9uUGF0aHMsICdURVNUX3Rlc3RHdWFyZE5vZGUnKS5yZXNvbHZlcyh0cnVlKTtcblxuICAgICAgZ2V0U25vZGVQb29sRnJvbURCT3JGZXRjaEZyb21TZWVkID0gc2FuZGJveFxuICAgICAgICAuc3R1YihTbm9kZVBvb2wsICdnZXRTbm9kZVBvb2xGcm9tREJPckZldGNoRnJvbVNlZWQnKVxuICAgICAgICAuY2FsbFRocm91Z2goKTtcbiAgICAgIGZldGNoRnJvbVNlZWRXaXRoUmV0cmllc0FuZFdyaXRlVG9EYiA9IHNhbmRib3hcbiAgICAgICAgLnN0dWIoU2VlZE5vZGVBUEksICdmZXRjaFNub2RlUG9vbEZyb21TZWVkTm9kZVdpdGhSZXRyaWVzJylcbiAgICAgICAgLnJlc29sdmVzKGZha2VTbm9kZVBvb2wpO1xuXG4gICAgICBzYW5kYm94LnN0dWIoRGF0YSwgJ3VwZGF0ZUd1YXJkTm9kZXMnKS5yZXNvbHZlcygpO1xuICAgICAgLy8gcnVuIHRoZSBjb21tYW5kXG4gICAgICBjb25zdCBndWFyZE5vZGVzID0gYXdhaXQgT25pb25QYXRocy5zZWxlY3RHdWFyZE5vZGVzKCk7XG5cbiAgICAgIGV4cGVjdChndWFyZE5vZGVzLmxlbmd0aCkudG8uYmUuZXF1YWwoMyk7XG4gICAgICBleHBlY3QodGVzdEd1YXJkTm9kZS5jYWxsQ291bnQpLnRvLmJlLmVxdWFsKDMpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Rocm93cyBpZiB3ZSBoYXZlIHRvIGZldGNoIGZyb20gc2VlZCwgZmV0Y2ggZnJvbSBzZWVkIGJ1dCBub3QgaGF2ZSBlbm91Z2ggZmV0Y2hlZCBzbm9kZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBpbnZhbGlkU25kb2RlUG9vbCA9IGZha2VTbm9kZVBvb2wuc2xpY2UoMCwgMTEpO1xuICAgICAgc2FuZGJveC5zdHViKERhdGEsICdnZXRTbm9kZVBvb2xGcm9tRGInKS5yZXNvbHZlcyhpbnZhbGlkU25kb2RlUG9vbCk7XG4gICAgICBUZXN0VXRpbHMuc3R1YldpbmRvdygnZ2V0U2VlZE5vZGVMaXN0JywgKCkgPT4gW3sgdXJsOiAnd2hhdGV2ZXInIH1dKTtcblxuICAgICAgZ2V0U25vZGVQb29sRnJvbURCT3JGZXRjaEZyb21TZWVkID0gc2FuZGJveFxuICAgICAgICAuc3R1YihTbm9kZVBvb2wsICdnZXRTbm9kZVBvb2xGcm9tREJPckZldGNoRnJvbVNlZWQnKVxuICAgICAgICAuY2FsbFRocm91Z2goKTtcbiAgICAgIGZldGNoRnJvbVNlZWRXaXRoUmV0cmllc0FuZFdyaXRlVG9EYiA9IHNhbmRib3hcbiAgICAgICAgLnN0dWIoU2VlZE5vZGVBUEksICdmZXRjaFNub2RlUG9vbEZyb21TZWVkTm9kZVdpdGhSZXRyaWVzJylcbiAgICAgICAgLnJlc29sdmVzKGludmFsaWRTbmRvZGVQb29sKTtcblxuICAgICAgc2FuZGJveC5zdHViKERhdGEsICd1cGRhdGVHdWFyZE5vZGVzJykucmVzb2x2ZXMoKTtcbiAgICAgIC8vIHJ1biB0aGUgY29tbWFuZFxuICAgICAgbGV0IHRocm93ZWRFcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgT25pb25QYXRocy5zZWxlY3RHdWFyZE5vZGVzKCk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93ZWRFcnJvciA9IGUubWVzc2FnZTtcbiAgICAgIH1cbiAgICAgIGV4cGVjdCh0aHJvd2VkRXJyb3IpLnRvLmJlLmVxdWFsKFxuICAgICAgICAnQ291bGQgbm90IHNlbGVjdCBndWFyZCBub2Rlcy4gTm90IGVub3VnaCBub2RlcyBpbiB0aGUgcG9vbDogMTEnXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7O0FBRUEsa0JBQWlCO0FBQ2pCLFlBQXVCO0FBRXZCLG1CQUF5QjtBQUV6Qix3QkFBMEI7QUFDMUIsdUJBQWtDO0FBQ2xDLFdBQXNCO0FBRXRCLDhCQUEyQjtBQUMzQixpQkFBNEI7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