Skip to content
This repository was archived by the owner on Dec 9, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions src/services/offlineService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import { MockFactory } from "../test/mockFactory";
import { OfflineService } from "./offlineService";

describe("Offline Service", () => {

const mySpawn = mockSpawn();
require("child_process").spawn = mySpawn;
mySpawn.setDefault(mySpawn.simple(0, "Exit code"));
let mySpawn;

function createService(sls?: Serverless): OfflineService {
return new OfflineService(
Expand All @@ -21,12 +18,16 @@ describe("Offline Service", () => {

beforeEach(() => {
// Mocking the file system so that files are not created in project directory
mockFs({})
mockFs({});

mySpawn = mockSpawn();
require("child_process").spawn = mySpawn;
mySpawn.setDefault(mySpawn.simple(0, "Exit code"));
});

afterEach(() => {
mockFs.restore();
})
});

it("builds required files for offline execution", async () => {
const sls = MockFactory.createTestServerless();
Expand Down Expand Up @@ -113,7 +114,12 @@ describe("Offline Service", () => {
rmdirSpy.mockRestore();
});

it("instructs users how to run locally", async () => {
it("calls func host start on Mac OS", async () => {
Object.defineProperty(process, "platform", {
value: "darwin",
writable: true,
});

const sls = MockFactory.createTestServerless();
const service = createService(sls);
await service.start();
Expand All @@ -123,4 +129,20 @@ describe("Offline Service", () => {
expect(call.command).toEqual("func");
expect(call.args).toEqual(["host", "start"]);
});

it("calls func host start on windows", async () => {
Object.defineProperty(process, "platform", {
value: "win32",
writable: true,
});

const sls = MockFactory.createTestServerless();
const service = createService(sls);
await service.start();
const calls = mySpawn.calls;
expect(calls).toHaveLength(1);
const call = calls[0];
expect(call.command).toEqual("func.cmd");
expect(call.args).toEqual(["host", "start"]);
});
});
71 changes: 21 additions & 50 deletions src/services/offlineService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { spawn } from "child_process";
import { spawn, SpawnOptions } from "child_process";
import fs from "fs";
import Serverless from "serverless";
import configConstants from "../config";
Expand Down Expand Up @@ -29,7 +29,7 @@ export class OfflineService extends BaseService {
await this.packageService.createBindings();
const filenames = Object.keys(this.localFiles);
for (const filename of filenames) {
if (!fs.existsSync(filename)){
if (!fs.existsSync(filename)) {
fs.writeFileSync(
filename,
this.localFiles[filename]
Expand All @@ -44,7 +44,7 @@ export class OfflineService extends BaseService {
await this.packageService.cleanUp();
const filenames = Object.keys(this.localFiles);
for (const filename of filenames) {
if (fs.existsSync(filename)){
if (fs.existsSync(filename)) {
this.log(`Removing file '${filename}'`);
fs.unlinkSync(filename)
}
Expand All @@ -62,59 +62,30 @@ export class OfflineService extends BaseService {
/**
* Spawn a Node child process with predefined environment variables
* @param command CLI Command - NO ARGS
* @param args Array of arguments for CLI command
* @param env Additional environment variables to be set in addition to
* predefined variables in `serverless.yml`
* @param spawnArgs Array of arguments for CLI command
*/
private spawn(command: string, args?: string[], env?: any): Promise<void> {
env = {
private spawn(command: string, spawnArgs?: string[]): Promise<void> {
if (process.platform === "win32") {
command += ".cmd";
}

const env = {
// Inherit environment from current process, most importantly, the PATH
...process.env,
// Environment variables from serverless config are king
...this.serverless.service.provider["environment"],
...env
}
this.log(`Spawning process '${command} ${args.join(" ")}'`);
this.log(`Spawning process '${command} ${spawnArgs.join(" ")}'`);
return new Promise((resolve, reject) => {
const childProcess = spawn(command, args, {env});

childProcess.stdout.on("data", (data) => {
this.log(data, {
color: configConstants.funcConsoleColor,
}, command);
});

childProcess.stderr.on("data", (data) => {
this.log(data, {
color: "red",
}, command);
})

childProcess.on("message", (message) => {
this.log(message, {
color: configConstants.funcConsoleColor,
}, command);
});

childProcess.on("error", (err) => {
this.log(`${err}`, {
color: "red"
}, command);
reject(err);
});
const spawnOptions: SpawnOptions = { env, stdio: "inherit" };
const childProcess = spawn(command, spawnArgs, spawnOptions);

childProcess.on("exit", (code) => {
this.log(`Exited with code: ${code}`, {
color: (code === 0) ? "green" : "red",
}, command);
});

childProcess.on("close", (code) => {
this.log(`Closed with code: ${code}`, {
color: (code === 0) ? "green" : "red",
}, command);
resolve();
});

childProcess.on("disconnect", () => {
this.log("Process disconnected");
if (code === 0) {
resolve();
} else {
reject();
}
});
});
}
Expand Down