Skip to content

Commit

Permalink
Merge pull request #1308 from zowe/next-test-unix-sockets-timothy
Browse files Browse the repository at this point in the history
Replace Daemon Communication Mechanism
  • Loading branch information
t1m0thyj authored Feb 17, 2022
2 parents ae50e22 + 13f6250 commit 79bf53c
Show file tree
Hide file tree
Showing 8 changed files with 446 additions and 155 deletions.
13 changes: 9 additions & 4 deletions .github/workflows/zowe-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:

- name: Use NPM v8
id: npm8
run: npm install -g npm@^8
run: npm install -g npm@~8.3.2

- name: Install Node Package Dependencies
id: install
Expand Down Expand Up @@ -129,11 +129,16 @@ jobs:
env:
PATH: ${{ github.workspace }}\__tests__\__resources__\application_instances;${{ env.PATH }}

- name: Integration Tests
id: integration
if: ${{ always() && steps.build.outcome == 'success' }}
- name: Integration Tests (Native)
id: integration-native
if: ${{ always() && steps.build.outcome == 'success' && !(github.event.inputs.test-type == 'binary' || github.event_name == 'push') }}
run: npm run test:integration >> integration-tests.txt

- name: Integration Tests (Daemon)
id: integration-daemon
if: ${{ always() && steps.build.outcome == 'success' && (github.event.inputs.test-type == 'binary' || github.event_name == 'push') }}
run: npm run test:integration -- --runInBand >> integration-tests.txt

- name: Archive Results
id: upload
if: ${{ always() && steps.build.outcome == 'success' }}
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Zowe CLI package will be documented in this file.

## Recent Changes

- **NEXT BREAKING** Enhancement: Use sockets and named pipes instead of ports for daemon communication for improved access control.

## `7.0.0-next.202202151759`

- BugFix: Updated Imperative to convert previously used profile property names into V2-compliant property names.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ let testEnvironment: ITestEnvironment<ITestPropertiesSchema>;
describe("Zowe native executable", () => {
const exeCantRunDaemonMsg1: string = "You cannot run this 'daemon' command while using the Zowe CLI native executable.";
const exeCantRunDaemonMsg2: string = "Copy and paste the following command instead:";
const EXIT_CODE_CANT_RUN_DAEMON_CMD: number = 107;
const EXIT_CODE_CANT_RUN_DAEMON_CMD: number = 108;

let zoweExePath: string;
let willRunZoweExe: boolean = true;
Expand Down
205 changes: 199 additions & 6 deletions packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@

jest.mock("net");
jest.mock("@zowe/imperative");
import * as fs from "fs";
import * as net from "net";
import * as os from "os";
import * as path from "path";
import Mock = jest.Mock;
import { Imperative } from "@zowe/imperative";
import { DaemonDecider } from "../../../src/daemon/DaemonDecider";
jest.mock("../../../src/daemon//DaemonClient");

describe("DaemonDecider tests", () => {
afterEach(() => {
delete process.env.ZOWE_DAEMON;
});

it("should call normal parse method if no daemon keyword", () => {

Expand Down Expand Up @@ -64,7 +70,7 @@ describe("DaemonDecider tests", () => {
// do nothing
});

const listen = jest.fn((port, hostname, method) => {
const listen = jest.fn((socket, method) => {
// do nothing
method();
});
Expand Down Expand Up @@ -109,7 +115,7 @@ describe("DaemonDecider tests", () => {
expect(err.message).toBe("data");
});

it("should set port based on env variable", () => {
it("should set socket based on env variable", () => {

const log = jest.fn(() => {
// do nothing
Expand All @@ -125,12 +131,199 @@ describe("DaemonDecider tests", () => {

const daemonDecider = new DaemonDecider(["anything"]);

const testPort = "1234";

const testSocket = "/fake/pipe/path";
(daemonDecider as any).mParms = ["one", "two", "--daemon"];
process.env.ZOWE_DAEMON = testPort;
process.env.ZOWE_DAEMON = testSocket;
(daemonDecider as any).initialParse();
expect((daemonDecider as any).mPort).toBe(parseInt(testPort, 10));
expect((daemonDecider as any).mSocket).toBe(process.platform === "win32" ? "\\\\.\\pipe\\" + testSocket : testSocket);

});

it("should not start a daemon", () => {
const log = jest.fn(() => {
// do nothing
});

const on = jest.fn((event, func) => {
// do nothing
});

const listen = jest.fn((event, func) => {
// do nothing
});

const parse = jest.fn( (data, context) => {
expect(data).toBe(undefined);
expect(context).toBe(undefined);
});

(Imperative as any) = {
api: {
appLogger: {
trace: log,
debug: log,
error: log
}
},
console: {
info: log
},
parse
};

const fn = net.createServer as Mock<typeof net.createServer>;
fn.mockImplementation((unusedclient, ...args: any[]) => {
return {on, listen};
});

const daemonDecider = new DaemonDecider(["node", "zowe", "--help"]);
daemonDecider.init();

expect((daemonDecider as any).mSocket).toBeUndefined();
expect((daemonDecider as any).startServer).toBeUndefined();
});

(process.platform === "win32" ? describe : describe.skip)("win32 tests", () => {
it("should use the default socket location (win32)", () => {
const log = jest.fn(() => {
// do nothing
});

const on = jest.fn((event, func) => {
// do nothing
});

const listen = jest.fn((event, func) => {
// do nothing
});

const parse = jest.fn( (data, context) => {
expect(data).toBe(undefined);
expect(context).toBe(undefined);
});

(Imperative as any) = {
api: {
appLogger: {
trace: log,
debug: log,
error: log
}
},
console: {
info: log
},
parse
};

const fn = net.createServer as Mock<typeof net.createServer>;
fn.mockImplementation((unusedclient, ...args: any[]) => {
return {on, listen};
});

const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]);
daemonDecider.init();

expect((daemonDecider as any).mSocket).toEqual(`\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`);
});
});

(process.platform !== "win32" ? describe : describe.skip)("non-win32 tests", () => {
it("should use the default socket location (not win32)", () => {
const log = jest.fn(() => {
// do nothing
});

const on = jest.fn((event, func) => {
// do nothing
});

const listen = jest.fn((event, func) => {
// do nothing
});

const parse = jest.fn( (data, context) => {
expect(data).toBe(undefined);
expect(context).toBe(undefined);
});

(Imperative as any) = {
api: {
appLogger: {
trace: log,
debug: log,
error: log
}
},
console: {
info: log
},
parse
};

const fn = net.createServer as Mock<typeof net.createServer>;
fn.mockImplementation((unusedclient, ...args: any[]) => {
return {on, listen};
});

const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]);
daemonDecider.init();

expect((daemonDecider as any).mSocket).toEqual(path.join(os.homedir(), ".zowe-daemon.sock"));
});

it("should try to delete an existing socket on *nix", () => {
const log = jest.fn(() => {
// do nothing
});

const on = jest.fn((event, func) => {
// do nothing
});

const listen = jest.fn((event, func) => {
// do nothing
});

const parse = jest.fn( (data, context) => {
expect(data).toBe(undefined);
expect(context).toBe(undefined);
});

(Imperative as any) = {
api: {
appLogger: {
trace: log,
debug: log,
error: log
}
},
console: {
info: log
},
parse
};

const fn = net.createServer as Mock<typeof net.createServer>;
fn.mockImplementation((unusedclient, ...args: any[]) => {
return {on, listen};
});

const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]);
const testSocket = "/fake/pipe/path";
process.env.ZOWE_DAEMON = testSocket;

const existsSyncSpy = jest.spyOn(fs, "existsSync");
existsSyncSpy.mockReturnValueOnce(true);

const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync");
unlinkSyncSpy.mockReturnValueOnce(true);

daemonDecider.init();
daemonDecider.runOrUseDaemon();

expect(existsSyncSpy).toHaveBeenCalledTimes(1);
expect(unlinkSyncSpy).toHaveBeenCalledTimes(1);
});
});
});
Loading

0 comments on commit 79bf53c

Please sign in to comment.