UNPKG

faastjs

Version:

Serverless batch computing made simple.

185 lines 27 kB
"use strict"; /** * The purpose of this test is to check that the trampoline function on google * can route calls, invoke the wrapper, and return values correctly, without * actually creating a cloud function. However, it does use real cloud queues. */ Object.defineProperty(exports, "__esModule", { value: true }); const ava_1 = require("ava"); const uuid_1 = require("uuid"); const google_faast_1 = require("../src/google/google-faast"); const google_queue_1 = require("../src/google/google-queue"); const google_trampoline_https_1 = require("../src/google/google-trampoline-https"); const google_trampoline_queue_1 = require("../src/google/google-trampoline-queue"); const provider_1 = require("../src/provider"); const serialize_1 = require("../src/serialize"); const wrapper_1 = require("../src/wrapper"); const funcs = require("./fixtures/functions"); const util_1 = require("./fixtures/util"); const shared_1 = require("../src/shared"); process.env.FAAST_SILENT = "true"; async function initGoogleResources() { const services = await (0, google_faast_1.initializeGoogleServices)(); const { google } = services; const pubsub = google.pubsub("v1"); const project = await google.auth.getProjectId(); const FunctionName = `faast-${(0, uuid_1.v4)()}`; const topic = await pubsub.projects.topics.create({ name: (0, google_faast_1.getResponseQueueTopic)(project, FunctionName) }); const topicName = topic.data.name; const subscriptionName = (0, google_faast_1.getResponseSubscription)(project, FunctionName); await pubsub.projects.subscriptions.create({ name: subscriptionName, requestBody: { topic: topicName } }); const resources = { topicName, subscriptionName, google }; return resources; } async function cleanupGoogleResources(resources) { const { google, subscriptionName, topicName } = resources; const pubsub = google.pubsub("v1"); // Give google a little time to propagate the existence of the queue. await (0, shared_1.sleep)(5000); await pubsub.projects.subscriptions.delete({ subscription: subscriptionName }); await pubsub.projects.topics.delete({ topic: topicName }); } async function getMessages(resources, kind, nExpected) { const { google, subscriptionName } = resources; const pubsub = google.pubsub("v1"); const metrics = new google_faast_1.GoogleMetrics(); const cancel = new Promise(_ => { }); const result = []; while (result.length < nExpected) { const messages = await (0, google_queue_1.receiveMessages)(pubsub, subscriptionName, metrics, cancel); result.push(...(0, provider_1.filterMessages)(messages.Messages, kind)); } return result; } (0, ava_1.default)((0, util_1.title)("google", "trampoline https mode with promise response"), async (t) => { const resources = await initGoogleResources(); try { const wrapper = new wrapper_1.Wrapper(funcs, { childProcess: false, wrapperLog: () => { } }); const { trampoline } = (0, google_trampoline_https_1.makeTrampoline)(wrapper); const arg = "promise with https on google"; const name = funcs.identityNum.name; const call = { callId: "42", name, args: (0, serialize_1.serializeFunctionArgs)(name, [arg], true), modulePath: "./fixtures/functions", ResponseQueueId: resources.topicName }; const headers = { "function-execution-id": "google-trampoline-test-function-execution-id" }; const request = { body: call, headers }; const response = { send: (_) => { } }; await trampoline(request, response); const [msg] = await getMessages(resources, "promise", 1); (0, util_1.expectMessage)(t, msg, "promise", arg); } finally { await cleanupGoogleResources(resources); } }); (0, ava_1.default)((0, util_1.title)("google", "trampoline https mode with async iterator response"), async (t) => { const resources = await initGoogleResources(); try { const wrapper = new wrapper_1.Wrapper(funcs, { childProcess: false, wrapperLog: () => { } }); const { trampoline } = (0, google_trampoline_https_1.makeTrampoline)(wrapper); const arg = ["async iterator with https on google", "second arg"]; const name = funcs.asyncGenerator.name; const call = { callId: "42", name, args: (0, serialize_1.serializeFunctionArgs)(name, [arg], true), modulePath: "./fixtures/functions", ResponseQueueId: resources.topicName }; const headers = { "function-execution-id": "google-trampoline-test-function-execution-id" }; const request = { body: call, headers }; const response = { send: (_) => { } }; await trampoline(request, response); const messages = await getMessages(resources, "iterator", arg.length + 1); (0, util_1.checkIteratorMessages)(t, messages, arg); } finally { await cleanupGoogleResources(resources); } }); (0, ava_1.default)((0, util_1.title)("google", "trampoline queue mode with promise response"), async (t) => { const resources = await initGoogleResources(); try { const arg = "promise with queue on google"; const wrapper = new wrapper_1.Wrapper(funcs, { childProcess: false, wrapperLog: () => { } }); const { trampoline } = (0, google_trampoline_queue_1.makeTrampoline)(wrapper); const name = funcs.identityNum.name; const call = { callId: "42", name, args: (0, serialize_1.serializeFunctionArgs)(name, [arg], true), modulePath: "./fixtures/functions", ResponseQueueId: resources.topicName }; const event = { data: Buffer.from((0, serialize_1.serialize)(call)).toString("base64") }; const context = { eventId: "", timestamp: "", eventType: "", resource: {} }; await trampoline(event, context); const [msg] = await getMessages(resources, "promise", 1); (0, util_1.expectMessage)(t, msg, "promise", arg); } finally { await cleanupGoogleResources(resources); } }); (0, ava_1.default)((0, util_1.title)("google", "trampoline queue mode with async iterator response"), async (t) => { const resources = await initGoogleResources(); try { const wrapper = new wrapper_1.Wrapper(funcs, { childProcess: false, wrapperLog: () => { } }); const arg = ["async iterator with queue on google"]; const { trampoline } = (0, google_trampoline_queue_1.makeTrampoline)(wrapper); const name = funcs.asyncGenerator.name; const call = { callId: "42", name, args: (0, serialize_1.serializeFunctionArgs)(name, [arg], true), modulePath: "./fixtures/functions", ResponseQueueId: resources.topicName }; const event = { data: Buffer.from((0, serialize_1.serialize)(call)).toString("base64") }; const context = { eventId: "", timestamp: "", eventType: "", resource: {} }; await trampoline(event, context); const messages = await getMessages(resources, "iterator", arg.length + 1); (0, util_1.checkIteratorMessages)(t, messages, arg); } finally { await cleanupGoogleResources(resources); } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ29vZ2xlLXRyYW1wb2xpbmUudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3Rlc3QvZ29vZ2xlLXRyYW1wb2xpbmUudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7QUFFSCw2QkFBdUI7QUFHdkIsK0JBQW9DO0FBQ3BDLDZEQUtvQztBQUNwQyw2REFBNkQ7QUFDN0QsbUZBQThGO0FBQzlGLG1GQUcrQztBQUMvQyw4Q0FBdUQ7QUFDdkQsZ0RBQW9FO0FBQ3BFLDRDQUF5QztBQUN6Qyw4Q0FBOEM7QUFDOUMsMENBQThFO0FBQzlFLDBDQUFzQztBQUV0QyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUM7QUFRbEMsS0FBSyxVQUFVLG1CQUFtQjtJQUM5QixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUEsdUNBQXdCLEdBQUUsQ0FBQztJQUNsRCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsUUFBUSxDQUFDO0lBQzVCLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbkMsTUFBTSxPQUFPLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ2pELE1BQU0sWUFBWSxHQUFHLFNBQVMsSUFBQSxTQUFNLEdBQUUsRUFBRSxDQUFDO0lBQ3pDLE1BQU0sS0FBSyxHQUFHLE1BQU0sTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzlDLElBQUksRUFBRSxJQUFBLG9DQUFxQixFQUFDLE9BQU8sRUFBRSxZQUFZLENBQUM7S0FDckQsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFLLENBQUM7SUFFbkMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFBLHNDQUF1QixFQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztJQUN4RSxNQUFNLE1BQU0s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R0FBRyxDQUFDLENBQUM7S0FDM0M7WUFBUztRQUNOLE1BQU0sc0JBQXNCLENBQUMsU0FBUyxDQUFDLENBQUM7S0FDM0M7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhlIHB1cnBvc2Ugb2YgdGhpcyB0ZXN0IGlzIHRvIGNoZWNrIHRoYXQgdGhlIHRyYW1wb2xpbmUgZnVuY3Rpb24gb24gZ29vZ2xlXG4gKiBjYW4gcm91dGUgY2FsbHMsIGludm9rZSB0aGUgd3JhcHBlciwgYW5kIHJldHVybiB2YWx1ZXMgY29ycmVjdGx5LCB3aXRob3V0XG4gKiBhY3R1YWxseSBjcmVhdGluZyBhIGNsb3VkIGZ1bmN0aW9uLiBIb3dldmVyLCBpdCBkb2VzIHVzZSByZWFsIGNsb3VkIHF1ZXVlcy5cbiAqL1xuXG5pbXBvcnQgdGVzdCBmcm9tIFwiYXZhXCI7XG5pbXBvcnQgeyBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgeyBHb29nbGVBcGlzIH0gZnJvbSBcImdvb2dsZWFwaXNcIjtcbmltcG9ydCB7IHY0IGFzIHV1aWR2NCB9IGZyb20gXCJ1dWlkXCI7XG5pbXBvcnQge1xuICAgIGdldFJlc3BvbnNlUXVldWVUb3BpYyxcbiAgICBnZXRSZXNwb25zZVN1YnNjcmlwdGlvbixcbiAgICBHb29nbGVNZXRyaWNzLFxuICAgIGluaXRpYWxpemVHb29nbGVTZXJ2aWNlc1xufSBmcm9tIFwiLi4vc3JjL2dvb2dsZS9nb29nbGUtZmFhc3RcIjtcbmltcG9ydCB7IHJlY2VpdmVNZXNzYWdlcyB9IGZyb20gXCIuLi9zcmMvZ29vZ2xlL2dvb2dsZS1xdWV1ZVwiO1xuaW1wb3J0IHsgbWFrZVRyYW1wb2xpbmUgYXMgbWFrZVRyYW1wb2xpbmVIdHRwcyB9IGZyb20gXCIuLi9zcmMvZ29vZ2xlL2dvb2dsZS10cmFtcG9saW5lLWh0dHBzXCI7XG5pbXBvcnQge1xuICAgIENsb3VkRnVuY3Rpb25Db250ZXh0LFxuICAgIG1ha2VUcmFtcG9saW5lIGFzIG1ha2VUcmFtcG9saW5lUXVldWVcbn0gZnJvbSBcIi4uL3NyYy9nb29nbGUvZ29vZ2xlLXRyYW1wb2xpbmUtcXVldWVcIjtcbmltcG9ydCB7IGZpbHRlck1lc3NhZ2VzLCBLaW5kIH0gZnJvbSBcIi4uL3NyYy9wcm92aWRlclwiO1xuaW1wb3J0IHsgc2VyaWFsaXplLCBzZXJpYWxpemVGdW5jdGlvbkFyZ3MgfSBmcm9tIFwiLi4vc3JjL3NlcmlhbGl6ZVwiO1xuaW1wb3J0IHsgV3JhcHBlciB9IGZyb20gXCIuLi9zcmMvd3JhcHBlclwiO1xuaW1wb3J0ICogYXMgZnVuY3MgZnJvbSBcIi4vZml4dHVyZXMvZnVuY3Rpb25zXCI7XG5pbXBvcnQgeyBjaGVja0l0ZXJhdG9yTWVzc2FnZXMsIGV4cGVjdE1lc3NhZ2UsIHRpdGxlIH0gZnJvbSBcIi4vZml4dHVyZXMvdXRpbFwiO1xuaW1wb3J0IHsgc2xlZXAgfSBmcm9tIFwiLi4vc3JjL3NoYXJlZFwiO1xuXG5wcm9jZXNzLmVudi5GQUFTVF9TSUxFTlQgPSBcInRydWVcIjtcblxuaW50ZXJmYWNlIEdvb2dsZVRyYW1wb2xpbmVUZXN0UmVzb3VyY2VzIHtcbiAgICB0b3BpY05hbWU6IHN0cmluZztcbiAgICBzdWJzY3JpcHRpb25OYW1lOiBzdHJpbmc7XG4gICAgZ29vZ2xlOiBHb29nbGVBcGlzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpbml0R29vZ2xlUmVzb3VyY2VzKCkge1xuICAgIGNvbnN0IHNlcnZpY2VzID0gYXdhaXQgaW5pdGlhbGl6ZUdvb2dsZVNlcnZpY2VzKCk7XG4gICAgY29uc3QgeyBnb29nbGUgfSA9IHNlcnZpY2VzO1xuICAgIGNvbnN0IHB1YnN1YiA9IGdvb2dsZS5wdWJzdWIoXCJ2MVwiKTtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ29vZ2xlLmF1dGguZ2V0UHJvamVjdElkKCk7XG4gICAgY29uc3QgRnVuY3Rpb25OYW1lID0gYGZhYXN0LSR7dXVpZHY0KCl9YDtcbiAgICBjb25zdCB0b3BpYyA9IGF3YWl0IHB1YnN1Yi5wcm9qZWN0cy50b3BpY3MuY3JlYXRlKHtcbiAgICAgICAgbmFtZTogZ2V0UmVzcG9uc2VRdWV1ZVRvcGljKHByb2plY3QsIEZ1bmN0aW9uTmFtZSlcbiAgICB9KTtcbiAgICBjb25zdCB0b3BpY05hbWUgPSB0b3BpYy5kYXRhLm5hbWUhO1xuXG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uTmFtZSA9IGdldFJlc3BvbnNlU3Vic2NyaXB0aW9uKHByb2plY3QsIEZ1bmN0aW9uTmFtZSk7XG4gICAgYXdhaXQgcHVic3ViLnByb2plY3RzLnN1YnNjcmlwdGlvbnMuY3JlYXRlKHtcbiAgICAgICAgbmFtZTogc3Vic2NyaXB0aW9uTmFtZSxcbiAgICAgICAgcmVxdWVzdEJvZHk6IHtcbiAgICAgICAgICAgIHRvcGljOiB0b3BpY05hbWVcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29uc3QgcmVzb3VyY2VzOiBHb29nbGVUcmFtcG9saW5lVGVzdFJlc291cmNlcyA9IHtcbiAgICAgICAgdG9waWNOYW1lLFxuICAgICAgICBzdWJzY3JpcHRpb25OYW1lLFxuICAgICAgICBnb29nbGVcbiAgICB9O1xuICAgIHJldHVybiByZXNvdXJjZXM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNsZWFudXBHb29nbGVSZXNvdXJjZXMocmVzb3VyY2VzOiBHb29nbGVUcmFtcG9saW5lVGVzdFJlc291cmNlcykge1xuICAgIGNvbnN0IHsgZ29vZ2xlLCBzdWJzY3JpcHRpb25OYW1lLCB0b3BpY05hbWUgfSA9IHJlc291cmNlcztcbiAgICBjb25zdCBwdWJzdWIgPSBnb29nbGUucHVic3ViKFwidjFcIik7XG4gICAgLy8gR2l2ZSBnb29nbGUgYSBsaXR0bGUgdGltZSB0byBwcm9wYWdhdGUgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgcXVldWUuXG4gICAgYXdhaXQgc2xlZXAoNTAwMCk7XG4gICAgYXdhaXQgcHVic3ViLnByb2plY3RzLnN1YnNjcmlwdGlvbnMuZGVsZXRlKHtcbiAgICAgICAgc3Vic2NyaXB0aW9uOiBzdWJzY3JpcHRpb25OYW1lXG4gICAgfSk7XG4gICAgYXdhaXQgcHVic3ViLnByb2plY3RzLnRvcGljcy5kZWxldGUoe1xuICAgICAgICB0b3BpYzogdG9waWNOYW1lXG4gICAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldE1lc3NhZ2VzPEsgZXh0ZW5kcyBLaW5kPihcbiAgICByZXNvdXJjZXM6IEdvb2dsZVRyYW1wb2xpbmVUZXN0UmVzb3VyY2VzLFxuICAgIGtpbmQ6IEssXG4gICAgbkV4cGVjdGVkOiBudW1iZXJcbikge1xuICAgIGNvbnN0IHsgZ29vZ2xlLCBzdWJzY3JpcHRpb25OYW1lIH0gPSByZXNvdXJjZXM7XG4gICAgY29uc3QgcHVic3ViID0gZ29vZ2xlLnB1YnN1YihcInYxXCIpO1xuICAgIGNvbnN0IG1ldHJpY3MgPSBuZXcgR29vZ2xlTWV0cmljcygpO1xuICAgIGNvbnN0IGNhbmNlbCA9IG5ldyBQcm9taXNlPHZvaWQ+KF8gPT4ge30pO1xuICAgIGNvbnN0IHJlc3VsdCA9IFtdO1xuICAgIHdoaWxlIChyZXN1bHQubGVuZ3RoIDwgbkV4cGVjdGVkKSB7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2VzID0gYXdhaXQgcmVjZWl2ZU1lc3NhZ2VzKHB1YnN1Yiwgc3Vic2NyaXB0aW9uTmFtZSwgbWV0cmljcywgY2FuY2VsKTtcbiAgICAgICAgcmVzdWx0LnB1c2goLi4uZmlsdGVyTWVzc2FnZXMobWVzc2FnZXMuTWVzc2FnZXMsIGtpbmQpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxudGVzdCh0aXRsZShcImdvb2dsZVwiLCBcInRyYW1wb2xpbmUgaHR0cHMgbW9kZSB3aXRoIHByb21pc2UgcmVzcG9uc2VcIiksIGFzeW5jIHQgPT4ge1xuICAgIGNvbnN0IHJlc291cmNlcyA9IGF3YWl0IGluaXRHb29nbGVSZXNvdXJjZXMoKTtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCB3cmFwcGVyID0gbmV3IFdyYXBwZXIoZnVuY3MsIHsgY2hpbGRQcm9jZXNzOiBmYWxzZSwgd3JhcHBlckxvZzogKCkgPT4ge30gfSk7XG4gICAgICAgIGNvbnN0IHsgdHJhbXBvbGluZSB9ID0gbWFrZVRyYW1wb2xpbmVIdHRwcyh3cmFwcGVyKTtcbiAgICAgICAgY29uc3QgYXJnID0gXCJwcm9taXNlIHdpdGggaHR0cHMgb24gZ29vZ2xlXCI7XG4gICAgICAgIGNvbnN0IG5hbWUgPSBmdW5jcy5pZGVudGl0eU51bS5uYW1lO1xuICAgICAgICBjb25zdCBjYWxsID0ge1xuICAgICAgICAgICAgY2FsbElkOiBcIjQyXCIsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgYXJnczogc2VyaWFsaXplRnVuY3Rpb25BcmdzKG5hbWUsIFthcmddLCB0cnVlKSxcbiAgICAgICAgICAgIG1vZHVsZVBhdGg6IFwiLi9maXh0dXJlcy9mdW5jdGlvbnNcIixcbiAgICAgICAgICAgIFJlc3BvbnNlUXVldWVJZDogcmVzb3VyY2VzLnRvcGljTmFtZVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGhlYWRlcnM6IFJlcXVlc3RbXCJoZWFkZXJzXCJdID0ge1xuICAgICAgICAgICAgXCJmdW5jdGlvbi1leGVjdXRpb24taWRcIjogXCJnb29nbGUtdHJhbXBvbGluZS10ZXN0LWZ1bmN0aW9uLWV4ZWN1dGlvbi1pZFwiXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgcmVxdWVzdCA9IHsgYm9keTogY2FsbCwgaGVhZGVycyB9IGFzIFJlcXVlc3Q7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0geyBzZW5kOiAoXzogYW55KSA9PiB7fSB9IGFzIFJlc3BvbnNlO1xuXG4gICAgICAgIGF3YWl0IHRyYW1wb2xpbmUocmVxdWVzdCwgcmVzcG9uc2UpO1xuXG4gICAgICAgIGNvbnN0IFttc2ddID0gYXdhaXQgZ2V0TWVzc2FnZXMocmVzb3VyY2VzLCBcInByb21pc2VcIiwgMSk7XG4gICAgICAgIGV4cGVjdE1lc3NhZ2UodCwgbXNnLCBcInByb21pc2VcIiwgYXJnKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBjbGVhbnVwR29vZ2xlUmVzb3VyY2VzKHJlc291cmNlcyk7XG4gICAgfVxufSk7XG5cbnRlc3QodGl0bGUoXCJnb29nbGVcIiwgXCJ0cmFtcG9saW5lIGh0dHBzIG1vZGUgd2l0aCBhc3luYyBpdGVyYXRvciByZXNwb25zZVwiKSwgYXN5bmMgdCA9PiB7XG4gICAgY29uc3QgcmVzb3VyY2VzID0gYXdhaXQgaW5pdEdvb2dsZVJlc291cmNlcygpO1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHdyYXBwZXIgPSBuZXcgV3JhcHBlcihmdW5jcywgeyBjaGlsZFByb2Nlc3M6IGZhbHNlLCB3cmFwcGVyTG9nOiAoKSA9PiB7fSB9KTtcbiAgICAgICAgY29uc3QgeyB0cmFtcG9saW5lIH0gPSBtYWtlVHJhbXBvbGluZUh0dHBzKHdyYXBwZXIpO1xuICAgICAgICBjb25zdCBhcmcgPSBbXCJhc3luYyBpdGVyYXRvciB3aXRoIGh0dHBzIG9uIGdvb2dsZVwiLCBcInNlY29uZCBhcmdcIl07XG4gICAgICAgIGNvbnN0IG5hbWUgPSBmdW5jcy5hc3luY0dlbmVyYXRvci5uYW1lO1xuICAgICAgICBjb25zdCBjYWxsID0ge1xuICAgICAgICAgICAgY2FsbElkOiBcIjQyXCIsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgYXJnczogc2VyaWFsaXplRnVuY3Rpb25BcmdzKG5hbWUsIFthcmddLCB0cnVlKSxcbiAgICAgICAgICAgIG1vZHVsZVBhdGg6IFwiLi9maXh0dXJlcy9mdW5jdGlvbnNcIixcbiAgICAgICAgICAgIFJlc3BvbnNlUXVldWVJZDogcmVzb3VyY2VzLnRvcGljTmFtZVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGhlYWRlcnM6IFJlcXVlc3RbXCJoZWFkZXJzXCJdID0ge1xuICAgICAgICAgICAgXCJmdW5jdGlvbi1leGVjdXRpb24taWRcIjogXCJnb29nbGUtdHJhbXBvbGluZS10ZXN0LWZ1bmN0aW9uLWV4ZWN1dGlvbi1pZFwiXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgcmVxdWVzdCA9IHsgYm9keTogY2FsbCwgaGVhZGVycyB9IGFzIFJlcXVlc3Q7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0geyBzZW5kOiAoXzogYW55KSA9PiB7fSB9IGFzIFJlc3BvbnNlO1xuXG4gICAgICAgIGF3YWl0IHRyYW1wb2xpbmUocmVxdWVzdCwgcmVzcG9uc2UpO1xuXG4gICAgICAgIGNvbnN0IG1lc3NhZ2VzID0gYXdhaXQgZ2V0TWVzc2FnZXMocmVzb3VyY2VzLCBcIml0ZXJhdG9yXCIsIGFyZy5sZW5ndGggKyAxKTtcbiAgICAgICAgY2hlY2tJdGVyYXRvck1lc3NhZ2VzKHQsIG1lc3NhZ2VzLCBhcmcpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGNsZWFudXBHb29nbGVSZXNvdXJjZXMocmVzb3VyY2VzKTtcbiAgICB9XG59KTtcblxudGVzdCh0aXRsZShcImdvb2dsZVwiLCBcInRyYW1wb2xpbmUgcXVldWUgbW9kZSB3aXRoIHByb21pc2UgcmVzcG9uc2VcIiksIGFzeW5jIHQgPT4ge1xuICAgIGNvbnN0IHJlc291cmNlcyA9IGF3YWl0IGluaXRHb29nbGVSZXNvdXJjZXMoKTtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBhcmcgPSBcInByb21pc2Ugd2l0aCBxdWV1ZSBvbiBnb29nbGVcIjtcbiAgICAgICAgY29uc3Qgd3JhcHBlciA9IG5ldyBXcmFwcGVyKGZ1bmNzLCB7IGNoaWxkUHJvY2VzczogZmFsc2UsIHdyYXBwZXJMb2c6ICgpID0+IHt9IH0pO1xuICAgICAgICBjb25zdCB7IHRyYW1wb2xpbmUgfSA9IG1ha2VUcmFtcG9saW5lUXVldWUod3JhcHBlcik7XG4gICAgICAgIGNvbnN0IG5hbWUgPSBmdW5jcy5pZGVudGl0eU51bS5uYW1lO1xuICAgICAgICBjb25zdCBjYWxsID0ge1xuICAgICAgICAgICAgY2FsbElkOiBcIjQyXCIsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgYXJnczogc2VyaWFsaXplRnVuY3Rpb25BcmdzKG5hbWUsIFthcmddLCB0cnVlKSxcbiAgICAgICAgICAgIG1vZHVsZVBhdGg6IFwiLi9maXh0dXJlcy9mdW5jdGlvbnNcIixcbiAgICAgICAgICAgIFJlc3BvbnNlUXVldWVJZDogcmVzb3VyY2VzLnRvcGljTmFtZVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBldmVudCA9IHtcbiAgICAgICAgICAgIGRhdGE6IEJ1ZmZlci5mcm9tKHNlcmlhbGl6ZShjYWxsKSkudG9TdHJpbmcoXCJiYXNlNjRcIilcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBjb250ZXh0OiBDbG91ZEZ1bmN0aW9uQ29udGV4dCA9IHtcbiAgICAgICAgICAgIGV2ZW50SWQ6IFwiXCIsXG4gICAgICAgICAgICB0aW1lc3RhbXA6IFwiXCIsXG4gICAgICAgICAgICBldmVudFR5cGU6IFwiXCIsXG4gICAgICAgICAgICByZXNvdXJjZToge31cbiAgICAgICAgfTtcblxuICAgICAgICBhd2FpdCB0cmFtcG9saW5lKGV2ZW50LCBjb250ZXh0KTtcblxuICAgICAgICBjb25zdCBbbXNnXSA9IGF3YWl0IGdldE1lc3NhZ2VzKHJlc291cmNlcywgXCJwcm9taXNlXCIsIDEpO1xuICAgICAgICBleHBlY3RNZXNzYWdlKHQsIG1zZywgXCJwcm9taXNlXCIsIGFyZyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgY2xlYW51cEdvb2dsZVJlc291cmNlcyhyZXNvdXJjZXMpO1xuICAgIH1cbn0pO1xuXG50ZXN0KHRpdGxlKFwiZ29vZ2xlXCIsIFwidHJhbXBvbGluZSBxdWV1ZSBtb2RlIHdpdGggYXN5bmMgaXRlcmF0b3IgcmVzcG9uc2VcIiksIGFzeW5jIHQgPT4ge1xuICAgIGNvbnN0IHJlc291cmNlcyA9IGF3YWl0IGluaXRHb29nbGVSZXNvdXJjZXMoKTtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCB3cmFwcGVyID0gbmV3IFdyYXBwZXIoZnVuY3MsIHsgY2hpbGRQcm9jZXNzOiBmYWxzZSwgd3JhcHBlckxvZzogKCkgPT4ge30gfSk7XG4gICAgICAgIGNvbnN0IGFyZyA9IFtcImFzeW5jIGl0ZXJhdG9yIHdpdGggcXVldWUgb24gZ29vZ2xlXCJdO1xuXG4gICAgICAgIGNvbnN0IHsgdHJhbXBvbGluZSB9ID0gbWFrZVRyYW1wb2xpbmVRdWV1ZSh3cmFwcGVyKTtcbiAgICAgICAgY29uc3QgbmFtZSA9IGZ1bmNzLmFzeW5jR2VuZXJhdG9yLm5hbWU7XG4gICAgICAgIGNvbnN0IGNhbGwgPSB7XG4gICAgICAgICAgICBjYWxsSWQ6IFwiNDJcIixcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICBhcmdzOiBzZXJpYWxpemVGdW5jdGlvbkFyZ3MobmFtZSwgW2FyZ10sIHRydWUpLFxuICAgICAgICAgICAgbW9kdWxlUGF0aDogXCIuL2ZpeHR1cmVzL2Z1bmN0aW9uc1wiLFxuICAgICAgICAgICAgUmVzcG9uc2VRdWV1ZUlkOiByZXNvdXJjZXMudG9waWNOYW1lXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGV2ZW50ID0ge1xuICAgICAgICAgICAgZGF0YTogQnVmZmVyLmZyb20oc2VyaWFsaXplKGNhbGwpKS50b1N0cmluZyhcImJhc2U2NFwiKVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGNvbnRleHQ6IENsb3VkRnVuY3Rpb25Db250ZXh0ID0ge1xuICAgICAgICAgICAgZXZlbnRJZDogXCJcIixcbiAgICAgICAgICAgIHRpbWVzdGFtcDogXCJcIixcbiAgICAgICAgICAgIGV2ZW50VHlwZTogXCJcIixcbiAgICAgICAgICAgIHJlc291cmNlOiB7fVxuICAgICAgICB9O1xuXG4gICAgICAgIGF3YWl0IHRyYW1wb2xpbmUoZXZlbnQsIGNvbnRleHQpO1xuXG4gICAgICAgIGNvbnN0IG1lc3NhZ2VzID0gYXdhaXQgZ2V0TWVzc2FnZXMocmVzb3VyY2VzLCBcIml0ZXJhdG9yXCIsIGFyZy5sZW5ndGggKyAxKTtcbiAgICAgICAgY2hlY2tJdGVyYXRvck1lc3NhZ2VzKHQsIG1lc3NhZ2VzLCBhcmcpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGNsZWFudXBHb29nbGVSZXNvdXJjZXMocmVzb3VyY2VzKTtcbiAgICB9XG59KTtcbiJdfQ==