Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
123 changes: 123 additions & 0 deletions __tests__/AzModuleInstaller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { AzModuleInstaller } from "../src/AzModuleInstaller";
import FileUtils from "../src/Utilities/FileUtils";
import Utils from "../src/Utilities/Utils";

jest.mock("@actions/core");
jest.mock("@actions/tool-cache");
jest.mock("../src/Utilities/ArchiveTools");

const mockPathExists = jest.fn();
FileUtils.pathExists = mockPathExists;
FileUtils.deleteFile = jest.fn();

const mockIsHostedAgent = jest.fn();
Utils.isHostedAgent = mockIsHostedAgent;
Utils.saveAzModule = jest.fn();

describe("Testing AzModuleInstaller", () => {
let savedRunnerOS: string;
beforeAll(() => {
savedRunnerOS = process.env.RUNNER_OS;
process.env.RUNNER_OS = "Windows";
});
afterAll(() => {
process.env.RUNNER_OS = savedRunnerOS;
});

beforeEach(() => {
jest.resetAllMocks();
mockIsHostedAgent.mockReturnValue(true);
mockPathExists.mockReturnValue(false);
});

test("install in case of private agent", async () => {
mockIsHostedAgent.mockReturnValue(false);
const installer = new AzModuleInstaller("latest");
const mockTry = jest.fn();
installer["tryInstallingLatest"] = mockTry;
installer["tryInstallFromFolder"] = mockTry;
installer["tryInstallFromZip"] = mockTry;
installer["tryInstallFromGHRelease"] = mockTry;
installer["tryInstallFromPSGallery"] = mockTry;
const result = await installer.install();
expect(result).toEqual({ isInstalled: false, moduleSource: "privateAgent" });
expect(mockTry).not.toBeCalled();
});
test("install with latest version", async () => {
const installer = new AzModuleInstaller("latest");
const spyTryInstallingLatest = jest.spyOn(<any>installer, "tryInstallingLatest");
const mockTryInstalledTrue = jest.fn(async () => expect(installer["installResult"]["isInstalled"]).toBeTruthy());
installer["tryInstallFromFolder"] = mockTryInstalledTrue;
installer["tryInstallFromZip"] = mockTryInstalledTrue;
installer["tryInstallFromGHRelease"] = mockTryInstalledTrue;
installer["tryInstallFromPSGallery"] = mockTryInstalledTrue;
const result = await installer.install();
expect(result).toEqual({ isInstalled: true, moduleSource: "hostedAgentFolder" });
expect(spyTryInstallingLatest).toBeCalledTimes(1);
expect(mockTryInstalledTrue).toBeCalledTimes(4);
});
test("install with version 1.1.1 available as folder", async () => {
mockPathExists.mockImplementation((path) => path === "C:\\Modules\\az_1.1.1");
const installer = new AzModuleInstaller("1.1.1");
const spyTryInstallingLatest = jest.spyOn(<any>installer, "tryInstallingLatest");
const spyTryInstallFromFolder = jest.spyOn(<any>installer, "tryInstallFromFolder");
const mockTryInstalledTrue = jest.fn(async () => expect(installer["installResult"]["isInstalled"]).toBeTruthy());
installer["tryInstallFromZip"] = mockTryInstalledTrue;
installer["tryInstallFromGHRelease"] = mockTryInstalledTrue;
installer["tryInstallFromPSGallery"] = mockTryInstalledTrue;
const result = await installer.install();
expect(result).toEqual({ isInstalled: true, moduleSource: "hostedAgentFolder" });
expect(spyTryInstallingLatest).toBeCalledTimes(1);
expect(spyTryInstallFromFolder).toBeCalledTimes(1);
expect(mockTryInstalledTrue).toBeCalledTimes(3);
});
test("install with version 1.1.1 available as zip", async () => {
mockPathExists.mockImplementation((path) => path === "C:\\Modules\\az_1.1.1.zip");
const installer = new AzModuleInstaller("1.1.1");
const spyTryInstallingLatest = jest.spyOn(<any>installer, "tryInstallingLatest");
const spyTryInstallFromFolder = jest.spyOn(<any>installer, "tryInstallFromFolder");
const spyTryInstallFromZip = jest.spyOn(<any>installer, "tryInstallFromZip");
const mockTryInstalledTrue = jest.fn(async () => expect(installer["installResult"]["isInstalled"]).toBeTruthy());
installer["tryInstallFromGHRelease"] = mockTryInstalledTrue;
installer["tryInstallFromPSGallery"] = mockTryInstalledTrue;
const result = await installer.install();
expect(result).toEqual({ isInstalled: true, moduleSource: "hostedAgentZip" });
expect(spyTryInstallingLatest).toBeCalledTimes(1);
expect(spyTryInstallFromFolder).toBeCalledTimes(1);
expect(spyTryInstallFromZip).toBeCalledTimes(1);
expect(mockTryInstalledTrue).toBeCalledTimes(2);
});
test("install with version 1.1.1 from GHRelease", async () => {
const installer = new AzModuleInstaller("1.1.1");
installer["getDownloadUrlFromGHRelease"] = jest.fn().mockReturnValue("downloadUrl");
const spyTryInstallingLatest = jest.spyOn(<any>installer, "tryInstallingLatest");
const spyTryInstallFromFolder = jest.spyOn(<any>installer, "tryInstallFromFolder");
const spyTryInstallFromZip = jest.spyOn(<any>installer, "tryInstallFromZip");
const spyTryInstallFromGHRelease = jest.spyOn(<any>installer, "tryInstallFromGHRelease");
const mockTryInstalledTrue = jest.fn(async () => expect(installer["installResult"]["isInstalled"]).toBeTruthy());
installer["tryInstallFromPSGallery"] = mockTryInstalledTrue;
const result = await installer.install();
expect(result).toEqual({ isInstalled: true, moduleSource: "hostedAgentGHRelease" });
expect(spyTryInstallingLatest).toBeCalledTimes(1);
expect(spyTryInstallFromFolder).toBeCalledTimes(1);
expect(spyTryInstallFromZip).toBeCalledTimes(1);
expect(spyTryInstallFromGHRelease).toBeCalledTimes(1);
expect(mockTryInstalledTrue).toBeCalledTimes(1);
});
test("install with version 1.1.1 from PSGallery", async () => {
const installer = new AzModuleInstaller("1.1.1");
installer["getDownloadUrlFromGHRelease"] = jest.fn().mockRejectedValue(new Error("Error getting versions manifest."));
const spyTryInstallingLatest = jest.spyOn(<any>installer, "tryInstallingLatest");
const spyTryInstallFromFolder = jest.spyOn(<any>installer, "tryInstallFromFolder");
const spyTryInstallFromZip = jest.spyOn(<any>installer, "tryInstallFromZip");
const spyTryInstallFromGHRelease = jest.spyOn(<any>installer, "tryInstallFromGHRelease");
const spyTryInstallFromPSGallery = jest.spyOn(<any>installer, "tryInstallFromPSGallery");
const result = await installer.install();
expect(result).toEqual({ isInstalled: true, moduleSource: "hostedAgentPSGallery" });
expect(spyTryInstallingLatest).toBeCalledTimes(1);
expect(spyTryInstallFromFolder).toBeCalledTimes(1);
expect(spyTryInstallFromZip).toBeCalledTimes(1);
expect(spyTryInstallFromGHRelease).toBeCalledTimes(1);
expect(spyTryInstallFromPSGallery).toBeCalledTimes(1);
});
});
22 changes: 22 additions & 0 deletions __tests__/Utilities/ArchiveTools.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ArchiveTools } from "../../src/Utilities/ArchiveTools";

jest.mock("@actions/core");

describe('Testing ArchiveTools', () => {
test('unzip using powershell to extract', async () => {
const archiveTool = new ArchiveTools();
archiveTool["unzipUsingPowerShell"] = jest.fn();
archiveTool["unzipUsing7Zip"] = jest.fn();
await archiveTool.unzip("/usr/share/az_1.1.1.zip", "/usr/share");
expect(archiveTool["unzipUsingPowerShell"]).toHaveBeenCalledTimes(1);
expect(archiveTool["unzipUsing7Zip"]).not.toHaveBeenCalled();
});
test('unzip using 7zip to extract', async () => {
const archiveTool = new ArchiveTools(true);
archiveTool["unzipUsingPowerShell"] = jest.fn();
archiveTool["unzipUsing7Zip"] = jest.fn();
await archiveTool.unzip("/usr/share/az_1.1.1.zip", "/usr/share");
expect(archiveTool["unzipUsingPowerShell"]).not.toHaveBeenCalled();
expect(archiveTool["unzipUsing7Zip"]).toHaveBeenCalledTimes(1);
});
});
91 changes: 91 additions & 0 deletions __tests__/Utilities/Utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import Utils from '../../src/Utilities/Utils';
import PowerShellToolRunner from '../../src/Utilities/PowerShellToolRunner';

jest.mock('../../src/Utilities/PowerShellToolRunner');
const mockPowerShellToolRunnerInit = jest.fn();
const mockExecutePowerShellCommand = jest.fn();
let mockExecutePowerShellCommandOutput = "";
mockExecutePowerShellCommand.mockImplementation((_script, options) => {
options.listeners.stdout(Buffer.from(mockExecutePowerShellCommandOutput));
});
let mockExecutePowerShellScriptBlockExitCode = 0;
const mockExecutePowerShellScriptBlock = jest.fn(async (_script) => mockExecutePowerShellScriptBlockExitCode);
PowerShellToolRunner.init = mockPowerShellToolRunnerInit;
PowerShellToolRunner.executePowerShellCommand = mockExecutePowerShellCommand;
PowerShellToolRunner.executePowerShellScriptBlock = mockExecutePowerShellScriptBlock;

const version: string = '9.0.0';
const moduleName: string = 'az';
Expand All @@ -20,15 +34,30 @@ describe('Testing isValidVersion', () => {
});

describe('Testing setPSModulePath', () => {
let savedRunnerOS: string;
beforeAll(() => {
savedRunnerOS = process.env.RUNNER_OS;
});
afterAll(() => {
process.env.RUNNER_OS = savedRunnerOS;
});

test('PSModulePath with azPSVersion non-empty', () => {
process.env.RUNNER_OS = "Windows";
Utils.setPSModulePath(version);
expect(process.env.PSModulePath).toContain(version);
});
test('PSModulePath with azPSVersion empty', () => {
process.env.RUNNER_OS = "Linux";
const prevPSModulePath = process.env.PSModulePath;
Utils.setPSModulePath();
expect(process.env.PSModulePath).not.toEqual(prevPSModulePath);
});
test('setPSModulePath should throw for MacOS', () => {
process.env.RUNNER_OS = "Darwin";
expect(() => Utils.setPSModulePath()).toThrow();
expect(() => Utils.setPSModulePath(version)).toThrow();
});
});

describe('Testing getLatestModule', () => {
Expand All @@ -55,3 +84,65 @@ describe('Testing checkModuleVersion', () => {
expect(checkModuleVersionSpy).toHaveBeenCalled();
});
});

describe('Testing isHostedAgent', () => {
beforeEach(() => {
jest.clearAllMocks();
});

test('Should return true when file layout check script returns true', async () => {
mockExecutePowerShellCommandOutput = "True";
const isHostedAgentResult = await Utils.isHostedAgent("/usr/share");
expect(mockPowerShellToolRunnerInit).toHaveBeenCalledTimes(1);
expect(mockExecutePowerShellCommand).toHaveBeenCalledTimes(1);
expect(mockExecutePowerShellCommand.mock.calls[0][0]).toBe('Test-Path (Join-Path "/usr/share" "az_*")');
expect(isHostedAgentResult).toBeTruthy();
});
test('Should return false when file layout check script returns false', async () => {
mockExecutePowerShellCommandOutput = "False";
const isHostedAgentResult = await Utils.isHostedAgent("/usr/share");
expect(isHostedAgentResult).toBeFalsy();
});
});

describe('Testing isGhes', () => {
let savedGhUrl: string;
beforeAll(() => {
savedGhUrl = process.env['GITHUB_SERVER_URL'];
});
afterAll(() => {
process.env['GITHUB_SERVER_URL'] = savedGhUrl;
});

test('Should return false when server url is github.com', () => {
process.env['GITHUB_SERVER_URL'] = "https://github.com";
expect(Utils.isGhes()).toBeFalsy();
});
test('Should return false when server url is not available', () => {
process.env['GITHUB_SERVER_URL'] = "";
expect(Utils.isGhes()).toBeFalsy();
})
test('Should return true when server url is not github.com', () => {
process.env['GITHUB_SERVER_URL'] = "https://github.contoso.com";
expect(Utils.isGhes()).toBeTruthy();
});
});

describe('Testing saveAzModule', () => {
beforeEach(() => {
jest.clearAllMocks();
});

test('Should run without throwing when script succeeds with exit code 0', async () => {
mockExecutePowerShellScriptBlockExitCode = 0;
await Utils.saveAzModule("1.1.1", "/usr/share/az_1.1.1");
expect(mockPowerShellToolRunnerInit).toHaveBeenCalledTimes(1);
expect(mockExecutePowerShellScriptBlock).toHaveBeenCalledTimes(1);
expect(mockExecutePowerShellScriptBlock.mock.calls[0][0]).toContain(
"Save-Module -Path /usr/share/az_1.1.1 -Name Az -RequiredVersion 1.1.1 -Force -ErrorAction Stop");
});
test('Should throw when script fails with non-zero exit code', async () => {
mockExecutePowerShellScriptBlockExitCode = 1;
expect(Utils.saveAzModule("1.1.1", "/usr/share/az_1.1.1")).rejects.toThrow();
});
});
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ inputs:
description: 'If this is true, this task will fail if any errors are written to the error pipeline, or if any data is written to the Standard Error stream.'
required: false
default: 'false'
githubToken:
description: Used to pull Az module from Azure/az-ps-module-versions. Since there's a default, this is typically not supplied by the user.
default: ${{ github.token }}
branding:
icon: 'login.svg'
color: 'blue'
Expand Down
Loading