mirror of
https://code.forgejo.org/actions/cache.git
synced 2025-04-20 03:46:17 +02:00
unit test coverage for caching multiple dirs
This commit is contained in:
parent
e0d1942524
commit
057d9de723
11 changed files with 161 additions and 80 deletions
29
.github/workflows/cache.yml
vendored
29
.github/workflows/cache.yml
vendored
|
@ -1,29 +0,0 @@
|
|||
name: Cache
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '12.x'
|
||||
- name: Restore npm cache
|
||||
uses: ./
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
dist
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('salt.txt') }}
|
||||
- run: npm install
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- run: npm run build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
10
.github/workflows/workflow.yml
vendored
10
.github/workflows/workflow.yml
vendored
|
@ -1,11 +1,11 @@
|
|||
name: Tests
|
||||
|
||||
on:
|
||||
# pull_request:
|
||||
# branches:
|
||||
# - master
|
||||
# paths-ignore:
|
||||
# - '**.md'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as core from "@actions/core";
|
||||
import * as glob from "@actions/glob";
|
||||
import * as io from "@actions/io";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { promises as fs } from "fs";
|
||||
|
||||
import { Events, Outputs, State } from "../src/constants";
|
||||
import { ArtifactCacheEntry } from "../src/contracts";
|
||||
|
@ -10,10 +11,19 @@ import * as actionUtils from "../src/utils/actionUtils";
|
|||
jest.mock("@actions/core");
|
||||
jest.mock("os");
|
||||
|
||||
function getTempDir(): string {
|
||||
return path.join(__dirname, "_temp", "actionUtils");
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
delete process.env[Events.Key];
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
delete process.env["GITHUB_WORKSPACE"];
|
||||
await io.rmRF(getTempDir());
|
||||
});
|
||||
|
||||
test("getArchiveFileSize returns file size", () => {
|
||||
const filePath = path.join(__dirname, "__fixtures__", "helloWorld.txt");
|
||||
|
||||
|
@ -183,13 +193,34 @@ test("isValidEvent returns false for unknown event", () => {
|
|||
});
|
||||
|
||||
test("resolvePaths with no ~ in path", async () => {
|
||||
// TODO: these test paths will need to exist
|
||||
const filePath = ".cache/yarn";
|
||||
const filePath = ".cache";
|
||||
|
||||
const resolvedPath = await actionUtils.resolvePaths([filePath]);
|
||||
// Create the following layout:
|
||||
// cwd
|
||||
// cwd/.cache
|
||||
// cwd/.cache/file.txt
|
||||
|
||||
const expectedPath = [path.resolve(filePath)];
|
||||
expect(resolvedPath).toStrictEqual(expectedPath);
|
||||
const root = path.join(getTempDir(), "no-tilde");
|
||||
// tarball entries will be relative to workspace
|
||||
process.env["GITHUB_WORKSPACE"] = root;
|
||||
|
||||
await fs.mkdir(root, { recursive: true });
|
||||
const cache = path.join(root, ".cache");
|
||||
await fs.mkdir(cache, { recursive: true });
|
||||
await fs.writeFile(path.join(cache, "file.txt"), "cached");
|
||||
|
||||
const originalCwd = process.cwd();
|
||||
|
||||
try {
|
||||
process.chdir(root);
|
||||
|
||||
const resolvedPath = await actionUtils.resolvePaths([filePath]);
|
||||
|
||||
const expectedPath = [filePath];
|
||||
expect(resolvedPath).toStrictEqual(expectedPath);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
test("resolvePaths with ~ in path", async () => {
|
||||
|
@ -201,26 +232,87 @@ test("resolvePaths with ~ in path", async () => {
|
|||
return homedir;
|
||||
});
|
||||
|
||||
const root = getTempDir();
|
||||
process.env["GITHUB_WORKSPACE"] = root;
|
||||
|
||||
const resolvedPath = await actionUtils.resolvePaths([filePath]);
|
||||
|
||||
const expectedPath = [path.join(homedir, ".cache/yarn")];
|
||||
const expectedPath = [
|
||||
path.relative(root, path.join(homedir, ".cache/yarn"))
|
||||
];
|
||||
expect(resolvedPath).toStrictEqual(expectedPath);
|
||||
});
|
||||
|
||||
test("resolvePaths with home not found", () => {
|
||||
test("resolvePaths with home not found", async () => {
|
||||
const filePath = "~/.cache/yarn";
|
||||
const homedirMock = jest.spyOn(os, "homedir");
|
||||
homedirMock.mockImplementation(() => {
|
||||
return "";
|
||||
});
|
||||
// const globMock = jest.spyOn(glob, "homedir");
|
||||
// globMock.mockImplementation(() => "");
|
||||
|
||||
expect(async () => await actionUtils.resolvePaths([filePath])).toThrow(
|
||||
"Unable to resolve `~` to HOME"
|
||||
await expect(actionUtils.resolvePaths([filePath])).rejects.toThrow(
|
||||
"Unable to determine HOME directory"
|
||||
);
|
||||
});
|
||||
|
||||
test("resolvePaths inclusion pattern returns found", async () => {
|
||||
const pattern = "*.ts";
|
||||
// Create the following layout:
|
||||
// inclusion-patterns
|
||||
// inclusion-patterns/miss.txt
|
||||
// inclusion-patterns/test.ts
|
||||
|
||||
const root = path.join(getTempDir(), "inclusion-patterns");
|
||||
// tarball entries will be relative to workspace
|
||||
process.env["GITHUB_WORKSPACE"] = root;
|
||||
|
||||
await fs.mkdir(root, { recursive: true });
|
||||
await fs.writeFile(path.join(root, "miss.txt"), "no match");
|
||||
await fs.writeFile(path.join(root, "test.ts"), "match");
|
||||
|
||||
const originalCwd = process.cwd();
|
||||
|
||||
try {
|
||||
process.chdir(root);
|
||||
|
||||
const resolvedPath = await actionUtils.resolvePaths([pattern]);
|
||||
|
||||
const expectedPath = ["test.ts"];
|
||||
expect(resolvedPath).toStrictEqual(expectedPath);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
test("resolvePaths exclusion pattern returns not found", async () => {
|
||||
const patterns = ["*.ts", "!test.ts"];
|
||||
// Create the following layout:
|
||||
// exclusion-patterns
|
||||
// exclusion-patterns/miss.txt
|
||||
// exclusion-patterns/test.ts
|
||||
|
||||
const root = path.join(getTempDir(), "exclusion-patterns");
|
||||
// tarball entries will be relative to workspace
|
||||
process.env["GITHUB_WORKSPACE"] = root;
|
||||
|
||||
await fs.mkdir(root, { recursive: true });
|
||||
await fs.writeFile(path.join(root, "miss.txt"), "no match");
|
||||
await fs.writeFile(path.join(root, "test.ts"), "no match");
|
||||
|
||||
const originalCwd = process.cwd();
|
||||
|
||||
try {
|
||||
process.chdir(root);
|
||||
|
||||
const resolvedPath = await actionUtils.resolvePaths(patterns);
|
||||
|
||||
const expectedPath = [];
|
||||
expect(resolvedPath).toStrictEqual(expectedPath);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
test("isValidEvent returns true for push event", () => {
|
||||
const event = Events.Push;
|
||||
process.env[Events.Key] = event;
|
||||
|
|
|
@ -55,7 +55,7 @@ test("restore with invalid event outputs warning", async () => {
|
|||
test("restore with no path should fail", async () => {
|
||||
const failedMock = jest.spyOn(core, "setFailed");
|
||||
await run();
|
||||
// TODO: this shouldn't be necessary if tarball contains entries relative to workspace
|
||||
// this input isn't necessary for restore b/c tarball contains entries relative to workspace
|
||||
expect(failedMock).not.toHaveBeenCalledWith(
|
||||
"Input required and not supplied: path"
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as core from "@actions/core";
|
||||
import * as path from "path";
|
||||
import * as cacheHttpClient from "../src/cacheHttpClient";
|
||||
import { Events, Inputs } from "../src/constants";
|
||||
import { Events, Inputs, CacheFilename } from "../src/constants";
|
||||
import { ArtifactCacheEntry } from "../src/contracts";
|
||||
import run from "../src/save";
|
||||
import * as tar from "../src/tar";
|
||||
|
@ -204,10 +204,10 @@ test("save with large cache outputs warning", async () => {
|
|||
|
||||
await run();
|
||||
|
||||
const archivePath = path.join("/foo/bar", "cache.tgz");
|
||||
const archiveFolder = "/foo/bar";
|
||||
|
||||
expect(createTarMock).toHaveBeenCalledTimes(1);
|
||||
expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePaths);
|
||||
expect(createTarMock).toHaveBeenCalledWith(archiveFolder, cachePaths);
|
||||
|
||||
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
||||
expect(logWarningMock).toHaveBeenCalledWith(
|
||||
|
@ -314,13 +314,14 @@ test("save with server error outputs warning", async () => {
|
|||
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey);
|
||||
|
||||
const archivePath = path.join("/foo/bar", "cache.tgz");
|
||||
const archiveFolder = "/foo/bar";
|
||||
const archiveFile = path.join(archiveFolder, CacheFilename);
|
||||
|
||||
expect(createTarMock).toHaveBeenCalledTimes(1);
|
||||
expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePaths);
|
||||
expect(createTarMock).toHaveBeenCalledWith(archiveFolder, cachePaths);
|
||||
|
||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archivePath);
|
||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile);
|
||||
|
||||
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
||||
expect(logWarningMock).toHaveBeenCalledWith("HTTP Error Occurred");
|
||||
|
@ -369,13 +370,14 @@ test("save with valid inputs uploads a cache", async () => {
|
|||
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey);
|
||||
|
||||
const archivePath = path.join("/foo/bar", "cache.tgz");
|
||||
const archiveFolder = "/foo/bar";
|
||||
const archiveFile = path.join(archiveFolder, CacheFilename);
|
||||
|
||||
expect(createTarMock).toHaveBeenCalledTimes(1);
|
||||
expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePaths);
|
||||
expect(createTarMock).toHaveBeenCalledWith(archiveFolder, cachePaths);
|
||||
|
||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archivePath);
|
||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile);
|
||||
|
||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
import * as exec from "@actions/exec";
|
||||
import * as io from "@actions/io";
|
||||
import { promises as fs } from "fs";
|
||||
import * as path from "path";
|
||||
import * as tar from "../src/tar";
|
||||
import { CacheFilename } from "../src/constants";
|
||||
|
||||
jest.mock("@actions/exec");
|
||||
jest.mock("@actions/io");
|
||||
|
||||
beforeAll(() => {
|
||||
function getTempDir(): string {
|
||||
return path.join(__dirname, "_temp", "tar");
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.spyOn(io, "which").mockImplementation(tool => {
|
||||
return Promise.resolve(tool);
|
||||
});
|
||||
|
||||
process.env["GITHUB_WORKSPACE"] = process.cwd();
|
||||
await jest.requireActual("@actions/io").rmRF(getTempDir());
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
afterAll(async () => {
|
||||
delete process.env["GITHUB_WORKSPACE"];
|
||||
await jest.requireActual("@actions/io").rmRF(getTempDir());
|
||||
});
|
||||
|
||||
test("extract tar", async () => {
|
||||
|
@ -33,36 +42,43 @@ test("extract tar", async () => {
|
|||
? `${process.env["windir"]}\\System32\\tar.exe`
|
||||
: "tar";
|
||||
expect(execMock).toHaveBeenCalledTimes(1);
|
||||
expect(execMock).toHaveBeenCalledWith(`"${tarPath}"`, [
|
||||
"-xz",
|
||||
"-f",
|
||||
archivePath,
|
||||
"-P",
|
||||
"-C",
|
||||
workspace
|
||||
]);
|
||||
expect(execMock).toHaveBeenCalledWith(
|
||||
`"${tarPath}"`,
|
||||
["-xz", "-f", archivePath, "-P", "-C", workspace],
|
||||
{ cwd: undefined }
|
||||
);
|
||||
});
|
||||
|
||||
test("create tar", async () => {
|
||||
const execMock = jest.spyOn(exec, "exec");
|
||||
|
||||
const archivePath = "cache.tar";
|
||||
const archiveFolder = getTempDir();
|
||||
const workspace = process.env["GITHUB_WORKSPACE"];
|
||||
const sourceDirectories = ["~/.npm/cache", `${workspace}/dist`];
|
||||
|
||||
await tar.createTar(archivePath, sourceDirectories);
|
||||
await fs.mkdir(archiveFolder, { recursive: true });
|
||||
|
||||
await tar.createTar(archiveFolder, sourceDirectories);
|
||||
|
||||
const IS_WINDOWS = process.platform === "win32";
|
||||
const tarPath = IS_WINDOWS
|
||||
? `${process.env["windir"]}\\System32\\tar.exe`
|
||||
: "tar";
|
||||
|
||||
expect(execMock).toHaveBeenCalledTimes(1);
|
||||
expect(execMock).toHaveBeenCalledWith(`"${tarPath}"`, [
|
||||
"-cz",
|
||||
"-f",
|
||||
archivePath,
|
||||
"-C",
|
||||
workspace,
|
||||
sourceDirectories.join(" ")
|
||||
]);
|
||||
expect(execMock).toHaveBeenCalledWith(
|
||||
`"${tarPath}"`,
|
||||
[
|
||||
"-cz",
|
||||
"-f",
|
||||
CacheFilename,
|
||||
"-C",
|
||||
workspace,
|
||||
"--files-from",
|
||||
"manifest.txt"
|
||||
],
|
||||
{
|
||||
cwd: archiveFolder
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
2
dist/restore/index.js
vendored
2
dist/restore/index.js
vendored
|
@ -4975,7 +4975,7 @@ function extractTar(archivePath) {
|
|||
exports.extractTar = extractTar;
|
||||
function createTar(archiveFolder, sourceDirectories) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// TODO: will want to stream sourceDirectories into tar
|
||||
// Write source directories to manifest.txt to avoid command length limits
|
||||
const manifestFilename = "manifest.txt";
|
||||
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join("\n"));
|
||||
const workingDirectory = getWorkingDirectory();
|
||||
|
|
2
dist/save/index.js
vendored
2
dist/save/index.js
vendored
|
@ -4963,7 +4963,7 @@ function extractTar(archivePath) {
|
|||
exports.extractTar = extractTar;
|
||||
function createTar(archiveFolder, sourceDirectories) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// TODO: will want to stream sourceDirectories into tar
|
||||
// Write source directories to manifest.txt to avoid command length limits
|
||||
const manifestFilename = "manifest.txt";
|
||||
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join("\n"));
|
||||
const workingDirectory = getWorkingDirectory();
|
||||
|
|
1
salt.txt
1
salt.txt
|
@ -1 +0,0 @@
|
|||
Fri Mar 6 11:28:08 PST 2020
|
|
@ -48,7 +48,7 @@ export async function createTar(
|
|||
archiveFolder: string,
|
||||
sourceDirectories: string[]
|
||||
): Promise<void> {
|
||||
// TODO: will want to stream sourceDirectories into tar
|
||||
// Write source directories to manifest.txt to avoid command length limits
|
||||
const manifestFilename = "manifest.txt";
|
||||
writeFileSync(
|
||||
path.join(archiveFolder, manifestFilename),
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as core from "@actions/core";
|
|||
import * as io from "@actions/io";
|
||||
import * as glob from "@actions/glob";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as uuidV4 from "uuid/v4";
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue