From 8f918c4a8c2b4f6da9c3ede00e2413b14c706598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BE=C3=B3r=20Magn=C3=BAsson?= Date: Mon, 5 Aug 2019 12:02:01 +0200 Subject: [PATCH] test: refactor tests for remote sources and add some more --- garden-service/src/util/fs.ts | 2 +- garden-service/src/vcs/git.ts | 3 +- garden-service/src/watch.ts | 4 +- garden-service/test/helpers.ts | 79 +++++-- .../.gardenignore | 2 - .../garden.yml | 5 - .../sources/module/module-a/.garden-version | 3 - .../sources/module/module-c/.garden-version | 3 - .../mock-local-path/module-a/.garden-version | 3 - .../mock-local-path/module-c/.garden-version | 3 - .../mock-local-path/module-c/garden.yml | 10 - .../module-a/.garden-version | 3 - .../module-a/garden.yml | 2 +- .../module-b/.garden-version | 3 - .../module-b/garden.yml | 2 +- .../module-c/.garden-version | 3 - .../module-c/garden.yml | 2 +- .../.gardenignore | 1 - .../garden.yml | 6 +- .../mock-dot-garden/local-config.yml | 0 .../project/source-a/module-a/.garden-version | 3 - .../source-a/module-a/.garden-version | 3 - .../source-a/module-a/garden.yml | 10 - .../source-b/module-b/garden.yml | 10 - .../source-c/module-c/garden.yml | 10 - .../README.md | 8 + .../module-a/foo.txt | 1 + .../module-a/garden.yml | 0 .../module-b/garden.yml | 0 .../module-c/garden.yml | 0 .../README.md | 8 + .../source-a/module-a/foo.txt | 1 + .../source-a/module-a/garden.yml | 0 .../source-b/module-b/garden.yml | 0 .../source-c/module-c/garden.yml | 0 garden-service/test/unit/src/commands/link.ts | 56 +++-- .../test/unit/src/commands/unlink.ts | 62 +++--- .../test/unit/src/commands/update-remote.ts | 37 +--- garden-service/test/unit/src/garden.ts | 148 ++++++------- .../test/unit/src/util/ext-source-util.ts | 6 +- garden-service/test/unit/src/watch.ts | 206 +++++++++++++++--- 41 files changed, 407 insertions(+), 301 deletions(-) delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/.gardenignore delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-a/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-c/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-a/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/garden.yml delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/module-a/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/module-b/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-module-sources/module-c/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/.gardenignore delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/local-config.yml delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-a/module-a/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/.garden-version delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/garden.yml delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-b/module-b/garden.yml delete mode 100644 garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-c/module-c/garden.yml create mode 100644 garden-service/test/unit/data/test-project-local-module-sources/README.md create mode 100644 garden-service/test/unit/data/test-project-local-module-sources/module-a/foo.txt rename garden-service/test/unit/data/{test-project-ext-module-sources/mock-local-path => test-project-local-module-sources}/module-a/garden.yml (100%) rename garden-service/test/unit/data/{test-project-ext-module-sources/mock-local-path => test-project-local-module-sources}/module-b/garden.yml (100%) rename garden-service/test/unit/data/{test-project-ext-module-sources/mock-dot-garden/sources/module => test-project-local-module-sources}/module-c/garden.yml (100%) create mode 100644 garden-service/test/unit/data/test-project-local-project-sources/README.md create mode 100644 garden-service/test/unit/data/test-project-local-project-sources/source-a/module-a/foo.txt rename garden-service/test/unit/data/{test-project-ext-project-sources/mock-dot-garden/sources/project => test-project-local-project-sources}/source-a/module-a/garden.yml (100%) rename garden-service/test/unit/data/{test-project-ext-project-sources/mock-dot-garden/sources/project => test-project-local-project-sources}/source-b/module-b/garden.yml (100%) rename garden-service/test/unit/data/{test-project-ext-project-sources/mock-dot-garden/sources/project => test-project-local-project-sources}/source-c/module-c/garden.yml (100%) diff --git a/garden-service/src/util/fs.ts b/garden-service/src/util/fs.ts index d273c55dc5f..d779d259a6f 100644 --- a/garden-service/src/util/fs.ts +++ b/garden-service/src/util/fs.ts @@ -21,7 +21,7 @@ import { VcsHandler } from "../vcs/vcs" const VALID_CONFIG_FILENAMES = ["garden.yml", "garden.yaml"] const metadataFilename = "metadata.json" export const defaultDotIgnoreFiles = [".gitignore", ".gardenignore"] -// FIXME: We should use `garden.gardenDirPath` instead of ".garden" since the dir name can be variable +// FIXME: We should use `garden.gardenDirPath` instead of ".garden" since the gardenDirPath property is configurable. export const fixedExcludes = [".git", ".garden/**/*", "debug-info*/**"] /* diff --git a/garden-service/src/vcs/git.ts b/garden-service/src/vcs/git.ts index 51c0301df2e..d9dc88935db 100644 --- a/garden-service/src/vcs/git.ts +++ b/garden-service/src/vcs/git.ts @@ -87,7 +87,8 @@ export class GitHandler extends VcsHandler { * We need to exclude .garden to avoid errors when path is the project root. This happens e.g. for modules * whose config is colocated with the project config, and that don't specify include paths/patterns. */ - // FIXME: We should use `garden.gardenDirPath` instead of ".garden" since the dir name can be variable + // FIXME: We should use `garden.gardenDirPath` instead of ".garden" since the gardenDirPath + // property is configurable. lines = await git("ls-files", "-s", "--others", "--exclude=.garden", path) // List ignored files from .gardenignore. We need to run ls-files twice to get both tracked and untracked files. diff --git a/garden-service/src/watch.ts b/garden-service/src/watch.ts index 2209a692df5..af15b55e584 100644 --- a/garden-service/src/watch.ts +++ b/garden-service/src/watch.ts @@ -22,7 +22,7 @@ import { isConfigFilename } from "./util/fs" let watcher: FSWatcher | undefined // Export so that we can clean up the global watcher instance when running tests -export function cleanUp() { +export function cleanUpGlobalWatcher() { if (watcher) { watcher.close() watcher = undefined @@ -30,7 +30,7 @@ export function cleanUp() { } // The process hangs after tests if we don't do this -registerCleanupFunction("stop watcher", cleanUp) +registerCleanupFunction("stop watcher", cleanUpGlobalWatcher) export type ChangeHandler = (module: Module | null, configChanged: boolean) => Promise diff --git a/garden-service/test/helpers.ts b/garden-service/test/helpers.ts index 305146e3f1f..ad21f20f60d 100644 --- a/garden-service/test/helpers.ts +++ b/garden-service/test/helpers.ts @@ -7,9 +7,12 @@ */ import * as td from "testdouble" +import Bluebird = require("bluebird") import { resolve, join } from "path" import { extend } from "lodash" -import { remove, readdirSync, existsSync } from "fs-extra" +import { remove, readdirSync, existsSync, copy, mkdirp, pathExists, truncate } from "fs-extra" +import execa = require("execa") + import { containerModuleSpecSchema, containerTestSchema, containerTaskSchema } from "../src/plugins/container/config" import { testExecModule, buildExecModule, execBuildSpecSchema } from "../src/plugins/exec" import { TaskResults } from "../src/task-graph" @@ -25,7 +28,7 @@ import { Garden, GardenParams } from "../src/garden" import { ModuleConfig } from "../src/config/module" import { mapValues, fromPairs } from "lodash" import { ModuleVersion } from "../src/vcs/vcs" -import { GARDEN_SERVICE_ROOT } from "../src/constants" +import { GARDEN_SERVICE_ROOT, LOCAL_CONFIG_FILENAME } from "../src/constants" import { EventBus, Events } from "../src/events" import { ValueOf } from "../src/util/util" import { LogEntry } from "../src/logger/log-entry" @@ -39,6 +42,7 @@ import { DeleteSecretParams } from "../src/types/plugin/provider/deleteSecret" import { RunServiceParams } from "../src/types/plugin/service/runService" import { RunTaskParams, RunTaskResult } from "../src/types/plugin/task/runTask" import { RunResult } from "../src/types/plugin/base" +import { ExternalSourceType, getRemoteSourceRelPath, hashRepoUrl } from "../src/util/ext-source-util" export const dataDir = resolve(GARDEN_SERVICE_ROOT, "test", "unit", "data") export const examplesDir = resolve(GARDEN_SERVICE_ROOT, "..", "examples") @@ -50,6 +54,10 @@ export const testModuleVersion: ModuleVersion = { files: [], } +// All test projects use this git URL +export const testGitUrl = "https://my-git-server.com/my-repo.git#master" +export const testGitUrlHash = hashRepoUrl(testGitUrl) + export function getDataDir(...names: string[]) { return resolve(dataDir, ...names) } @@ -379,20 +387,6 @@ export const cleanProject = async (gardenDirPath: string) => { return remove(gardenDirPath) } -/** - * Prevents git cloning. Use if creating a Garden instance with test-project-ext-module-sources - * or test-project-ext-project-sources as project root. - */ -export function stubExtSources(garden: Garden) { - td.replace(garden.vcs, "cloneRemoteSource", async () => undefined) - td.replace(garden.vcs, "updateRemoteSource", async () => undefined) - - const getRemoteSourcesDirname = td.replace(garden.vcs, "getRemoteSourcesDirname") - - td.when(getRemoteSourcesDirname("module")).thenReturn(join("sources", "module")) - td.when(getRemoteSourcesDirname("project")).thenReturn(join("sources", "project")) -} - export function getExampleProjects() { const names = readdirSync(examplesDir).filter(n => { const basePath = join(examplesDir, n) @@ -416,3 +410,56 @@ export function freezeTime(date?: Date) { timekeeper.freeze(date) return date } + +export async function resetLocalConfig(gardenDirPath: string) { + const path = join(gardenDirPath, LOCAL_CONFIG_FILENAME) + if (await pathExists(path)) { + await truncate(path) + } +} + +/** + * Idempotently initializes the test-project-ext-project-sources project and returns + * the Garden class. + */ +export async function makeExtProjectSourcesGarden() { + const projectRoot = resolve(dataDir, "test-project-ext-project-sources") + // Borrow the external sources from here: + const extSourcesRoot = resolve(dataDir, "test-project-local-project-sources") + const sourceNames = ["source-a", "source-b", "source-c"] + return prepareRemoteGarden({ projectRoot, extSourcesRoot, sourceNames, type: "project" }) +} + +/** + * Idempotently initializes the test-project-ext-project-sources project and returns + * the Garden class. + */ +export async function makeExtModuleSourcesGarden() { + const projectRoot = resolve(dataDir, "test-project-ext-module-sources") + // Borrow the external sources from here: + const extSourcesRoot = resolve(dataDir, "test-project-local-module-sources") + const sourceNames = ["module-a", "module-b", "module-c"] + return prepareRemoteGarden({ projectRoot, extSourcesRoot, sourceNames, type: "module" }) +} + +/** + * Helper function for idempotently initializing the ext-sources projects. + * Copies the external sources into the .garden directory and git inits them. + */ +async function prepareRemoteGarden({ + projectRoot, extSourcesRoot, sourceNames, type, +}: { projectRoot: string, extSourcesRoot: string, sourceNames: string[], type: ExternalSourceType }) { + const garden = await makeTestGarden(projectRoot) + const sourcesPath = join(projectRoot, ".garden", "sources", type) + + await mkdirp(sourcesPath) + // Copy the sources to the `.garden/sources` dir and git init them + await Bluebird.map(sourceNames, async (name) => { + const remoteSourceRelPath = getRemoteSourceRelPath({ name, url: testGitUrl, sourceType: type }) + const targetPath = join(projectRoot, ".garden", remoteSourceRelPath) + await copy(join(extSourcesRoot, name), targetPath) + await execa("git", ["init"], { cwd: targetPath }) + }) + + return garden +} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/.gardenignore b/garden-service/test/unit/data/test-project-ext-module-sources/.gardenignore deleted file mode 100644 index 60190f7fb76..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/.gardenignore +++ /dev/null @@ -1,2 +0,0 @@ -mock-dot-garden -mock-local-path diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/garden.yml b/garden-service/test/unit/data/test-project-ext-module-sources/garden.yml index 167fb33edda..b3681f17096 100644 --- a/garden-service/test/unit/data/test-project-ext-module-sources/garden.yml +++ b/garden-service/test/unit/data/test-project-ext-module-sources/garden.yml @@ -1,11 +1,6 @@ project: name: test-project-ext-project-sources - environmentDefaults: - variables: - some: variable environments: - name: local providers: - name: test-plugin - - name: test-plugin-b - - name: other diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-a/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-a/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-a/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-c/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-c/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-c/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-a/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-a/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-a/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/garden.yml b/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/garden.yml deleted file mode 100644 index f1b985f5cde..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-c/garden.yml +++ /dev/null @@ -1,10 +0,0 @@ -module: - name: module-c - type: test - services: - - name: service-c - build: - command: [echo, A] - tests: - - name: unit - command: [echo, OK] \ No newline at end of file diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/module-a/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/module-a/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/module-a/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/module-a/garden.yml b/garden-service/test/unit/data/test-project-ext-module-sources/module-a/garden.yml index dbbe2dee849..1c676692937 100644 --- a/garden-service/test/unit/data/test-project-ext-module-sources/module-a/garden.yml +++ b/garden-service/test/unit/data/test-project-ext-module-sources/module-a/garden.yml @@ -1,6 +1,6 @@ module: name: module-a - repositoryUrl: https://my-git-server.com/module-a.git#master + repositoryUrl: https://my-git-server.com/my-repo.git#master type: test services: - name: service-a diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/module-b/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/module-b/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/module-b/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/module-b/garden.yml b/garden-service/test/unit/data/test-project-ext-module-sources/module-b/garden.yml index 6e8a0f38d3c..605627eaed0 100644 --- a/garden-service/test/unit/data/test-project-ext-module-sources/module-b/garden.yml +++ b/garden-service/test/unit/data/test-project-ext-module-sources/module-b/garden.yml @@ -1,6 +1,6 @@ module: name: module-b - repositoryUrl: https://my-git-server.com/module-b.git#master + repositoryUrl: https://my-git-server.com/my-repo.git#master type: test services: - name: service-b diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/module-c/.garden-version b/garden-service/test/unit/data/test-project-ext-module-sources/module-c/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-module-sources/module-c/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/module-c/garden.yml b/garden-service/test/unit/data/test-project-ext-module-sources/module-c/garden.yml index cb920ef357e..40ed3a37f26 100644 --- a/garden-service/test/unit/data/test-project-ext-module-sources/module-c/garden.yml +++ b/garden-service/test/unit/data/test-project-ext-module-sources/module-c/garden.yml @@ -1,6 +1,6 @@ module: name: module-c - repositoryUrl: https://my-git-server.com/module-c.git#master + repositoryUrl: https://my-git-server.com/my-repo.git#master type: test services: - name: service-c diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/.gardenignore b/garden-service/test/unit/data/test-project-ext-project-sources/.gardenignore deleted file mode 100644 index 5a1d12bad47..00000000000 --- a/garden-service/test/unit/data/test-project-ext-project-sources/.gardenignore +++ /dev/null @@ -1 +0,0 @@ -mock-dot-garden \ No newline at end of file diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/garden.yml b/garden-service/test/unit/data/test-project-ext-project-sources/garden.yml index 40f48d12b8c..4384cf35557 100644 --- a/garden-service/test/unit/data/test-project-ext-project-sources/garden.yml +++ b/garden-service/test/unit/data/test-project-ext-project-sources/garden.yml @@ -2,11 +2,11 @@ project: name: test-project-ext-project-sources sources: - name: source-a - repositoryUrl: https://my-git-server.com/source-a.git#master + repositoryUrl: https://my-git-server.com/my-repo.git#master - name: source-b - repositoryUrl: https://my-git-server.com/source-b.git#master + repositoryUrl: https://my-git-server.com/my-repo.git#master - name: source-c - repositoryUrl: https://my-git-server.com/source-c.git#master + repositoryUrl: https://my-git-server.com/my-repo.git#master environmentDefaults: variables: some: variable diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/local-config.yml b/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/local-config.yml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-a/module-a/.garden-version b/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-a/module-a/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-a/module-a/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/.garden-version b/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/.garden-version deleted file mode 100644 index eb45f3a14b7..00000000000 --- a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/.garden-version +++ /dev/null @@ -1,3 +0,0 @@ -{ - "contentHash": "1234567890" -} diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/garden.yml b/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/garden.yml deleted file mode 100644 index e1d3a70ed8c..00000000000 --- a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-a/module-a/garden.yml +++ /dev/null @@ -1,10 +0,0 @@ -module: - name: module-a - type: test - services: - - name: service-a - build: - command: [echo, A] - tests: - - name: unit - command: [echo, OK] diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-b/module-b/garden.yml b/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-b/module-b/garden.yml deleted file mode 100644 index f9a06fdcb43..00000000000 --- a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-b/module-b/garden.yml +++ /dev/null @@ -1,10 +0,0 @@ -module: - name: module-b - type: test - services: - - name: service-b - build: - command: [echo, A] - tests: - - name: unit - command: [echo, OK] diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-c/module-c/garden.yml b/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-c/module-c/garden.yml deleted file mode 100644 index e6fe7199f9a..00000000000 --- a/garden-service/test/unit/data/test-project-ext-project-sources/mock-local-path/source-c/module-c/garden.yml +++ /dev/null @@ -1,10 +0,0 @@ -module: - name: module-c - type: test - services: - - name: service-c - build: - command: [echo, A] - tests: - - name: unit - command: [echo, OK] diff --git a/garden-service/test/unit/data/test-project-local-module-sources/README.md b/garden-service/test/unit/data/test-project-local-module-sources/README.md new file mode 100644 index 00000000000..c9bda6a10d0 --- /dev/null +++ b/garden-service/test/unit/data/test-project-local-module-sources/README.md @@ -0,0 +1,8 @@ +This is a dummy local version of a remote module source. That is, a remote module that a user has a copy of on their local machine and wants to link to. + +Used by the `test-project-ext-module-sources` project for linking its modules to a local path. Equivalent to the following: + +```sh +# In test-project-ext-module-sources dir +garden link module module-a ../test-project-local-module-sources/module-a +``` \ No newline at end of file diff --git a/garden-service/test/unit/data/test-project-local-module-sources/module-a/foo.txt b/garden-service/test/unit/data/test-project-local-module-sources/module-a/foo.txt new file mode 100644 index 00000000000..ba0e162e1c4 --- /dev/null +++ b/garden-service/test/unit/data/test-project-local-module-sources/module-a/foo.txt @@ -0,0 +1 @@ +bar \ No newline at end of file diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-a/garden.yml b/garden-service/test/unit/data/test-project-local-module-sources/module-a/garden.yml similarity index 100% rename from garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-a/garden.yml rename to garden-service/test/unit/data/test-project-local-module-sources/module-a/garden.yml diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-b/garden.yml b/garden-service/test/unit/data/test-project-local-module-sources/module-b/garden.yml similarity index 100% rename from garden-service/test/unit/data/test-project-ext-module-sources/mock-local-path/module-b/garden.yml rename to garden-service/test/unit/data/test-project-local-module-sources/module-b/garden.yml diff --git a/garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-c/garden.yml b/garden-service/test/unit/data/test-project-local-module-sources/module-c/garden.yml similarity index 100% rename from garden-service/test/unit/data/test-project-ext-module-sources/mock-dot-garden/sources/module/module-c/garden.yml rename to garden-service/test/unit/data/test-project-local-module-sources/module-c/garden.yml diff --git a/garden-service/test/unit/data/test-project-local-project-sources/README.md b/garden-service/test/unit/data/test-project-local-project-sources/README.md new file mode 100644 index 00000000000..9664d3e251f --- /dev/null +++ b/garden-service/test/unit/data/test-project-local-project-sources/README.md @@ -0,0 +1,8 @@ +This is a dummy local version of a remote project source. That is, a remote source that a user has a copy of on their local machine and wants to link to. + +Used by the `test-project-ext-project-sources` project for linking its sources to a local path. Equivalent to the following: + +```sh +# In test-project-ext-project-sources dir +garden link source source-a ../test-project-local-project-sources/source-a +``` \ No newline at end of file diff --git a/garden-service/test/unit/data/test-project-local-project-sources/source-a/module-a/foo.txt b/garden-service/test/unit/data/test-project-local-project-sources/source-a/module-a/foo.txt new file mode 100644 index 00000000000..ba0e162e1c4 --- /dev/null +++ b/garden-service/test/unit/data/test-project-local-project-sources/source-a/module-a/foo.txt @@ -0,0 +1 @@ +bar \ No newline at end of file diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-a/module-a/garden.yml b/garden-service/test/unit/data/test-project-local-project-sources/source-a/module-a/garden.yml similarity index 100% rename from garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-a/module-a/garden.yml rename to garden-service/test/unit/data/test-project-local-project-sources/source-a/module-a/garden.yml diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-b/module-b/garden.yml b/garden-service/test/unit/data/test-project-local-project-sources/source-b/module-b/garden.yml similarity index 100% rename from garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-b/module-b/garden.yml rename to garden-service/test/unit/data/test-project-local-project-sources/source-b/module-b/garden.yml diff --git a/garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-c/module-c/garden.yml b/garden-service/test/unit/data/test-project-local-project-sources/source-c/module-c/garden.yml similarity index 100% rename from garden-service/test/unit/data/test-project-ext-project-sources/mock-dot-garden/sources/project/source-c/module-c/garden.yml rename to garden-service/test/unit/data/test-project-local-project-sources/source-c/module-c/garden.yml diff --git a/garden-service/test/unit/src/commands/link.ts b/garden-service/test/unit/src/commands/link.ts index afdb60f592a..7fff25e30f3 100644 --- a/garden-service/test/unit/src/commands/link.ts +++ b/garden-service/test/unit/src/commands/link.ts @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2018 Garden Technologies, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + import { expect } from "chai" import { join } from "path" @@ -5,43 +13,30 @@ import { LinkModuleCommand } from "../../../../src/commands/link/module" import { getDataDir, expectError, - cleanProject, - stubExtSources, - makeTestGarden, withDefaultGlobalOpts, + makeExtProjectSourcesGarden, + makeExtModuleSourcesGarden, + resetLocalConfig, } from "../../../helpers" import { LinkSourceCommand } from "../../../../src/commands/link/source" import { Garden } from "../../../../src/garden" import { LogEntry } from "../../../../src/logger/log-entry" -import { ModuleVersion } from "../../../../src/vcs/vcs" -import * as td from "testdouble" describe("LinkCommand", () => { let garden: Garden let log: LogEntry - const dummyVersion: ModuleVersion = { - versionString: "foo", - dependencyVersions: {}, - files: [], - } - describe("LinkModuleCommand", () => { const cmd = new LinkModuleCommand() - const projectRoot = getDataDir("test-project-ext-module-sources") + const localModulePath = join(getDataDir("test-project-local-module-sources"), "module-a") beforeEach(async () => { - garden = await makeTestGarden(projectRoot) + garden = await makeExtModuleSourcesGarden() log = garden.log - stubExtSources(garden) - const resolveVersion = td.replace(garden, "resolveVersion") - td.when(resolveVersion("module-a", [])).thenResolve(dummyVersion) - td.when(resolveVersion("module-b", [])).thenResolve(dummyVersion) - td.when(resolveVersion("module-c", [])).thenResolve(dummyVersion) }) afterEach(async () => { - await cleanProject(garden.gardenDirPath) + await resetLocalConfig(garden.gardenDirPath) }) it("should link external modules", async () => { @@ -52,7 +47,7 @@ describe("LinkCommand", () => { footerLog: log, args: { module: "module-a", - path: join(projectRoot, "mock-local-path", "module-a"), + path: localModulePath, }, opts: withDefaultGlobalOpts({}), }) @@ -60,7 +55,7 @@ describe("LinkCommand", () => { const { linkedModuleSources } = await garden.configStore.get() expect(linkedModuleSources).to.eql([ - { name: "module-a", path: join(projectRoot, "mock-local-path", "module-a") }, + { name: "module-a", path: localModulePath }, ]) }) @@ -72,7 +67,7 @@ describe("LinkCommand", () => { footerLog: log, args: { module: "module-a", - path: join("mock-local-path", "module-a"), + path: join("..", "test-project-local-module-sources", "module-a"), }, opts: withDefaultGlobalOpts({}), }) @@ -80,7 +75,7 @@ describe("LinkCommand", () => { const { linkedModuleSources } = await garden.configStore.get() expect(linkedModuleSources).to.eql([ - { name: "module-a", path: join(projectRoot, "mock-local-path", "module-a") }, + { name: "module-a", path: localModulePath }, ]) }) @@ -104,16 +99,15 @@ describe("LinkCommand", () => { describe("LinkSourceCommand", () => { const cmd = new LinkSourceCommand() - const projectRoot = getDataDir("test-project-ext-project-sources") + const localSourcePath = join(getDataDir("test-project-local-project-sources"), "source-a") beforeEach(async () => { - garden = await makeTestGarden(projectRoot) + garden = await makeExtProjectSourcesGarden() log = garden.log - stubExtSources(garden) }) afterEach(async () => { - await cleanProject(garden.gardenDirPath) + await resetLocalConfig(garden.gardenDirPath) }) it("should link external sources", async () => { @@ -124,7 +118,7 @@ describe("LinkCommand", () => { footerLog: log, args: { source: "source-a", - path: join(projectRoot, "mock-local-path", "source-a"), + path: localSourcePath, }, opts: withDefaultGlobalOpts({}), }) @@ -132,7 +126,7 @@ describe("LinkCommand", () => { const { linkedProjectSources } = await garden.configStore.get() expect(linkedProjectSources).to.eql([ - { name: "source-a", path: join(projectRoot, "mock-local-path", "source-a") }, + { name: "source-a", path: localSourcePath }, ]) }) @@ -144,7 +138,7 @@ describe("LinkCommand", () => { footerLog: log, args: { source: "source-a", - path: join("mock-local-path", "source-a"), + path: join("..", "test-project-local-project-sources", `source-a`), }, opts: withDefaultGlobalOpts({}), }) @@ -152,7 +146,7 @@ describe("LinkCommand", () => { const { linkedProjectSources } = await garden.configStore.get() expect(linkedProjectSources).to.eql([ - { name: "source-a", path: join(projectRoot, "mock-local-path", "source-a") }, + { name: "source-a", path: localSourcePath }, ]) }) }) diff --git a/garden-service/test/unit/src/commands/unlink.ts b/garden-service/test/unit/src/commands/unlink.ts index 2a98cb43510..4a436fd0a94 100644 --- a/garden-service/test/unit/src/commands/unlink.ts +++ b/garden-service/test/unit/src/commands/unlink.ts @@ -5,43 +5,33 @@ import { LinkModuleCommand } from "../../../../src/commands/link/module" import { UnlinkModuleCommand } from "../../../../src/commands/unlink/module" import { getDataDir, - stubExtSources, - cleanProject, - makeTestGarden, withDefaultGlobalOpts, + makeExtProjectSourcesGarden, + makeExtModuleSourcesGarden, + resetLocalConfig, } from "../../../helpers" import { LinkSourceCommand } from "../../../../src/commands/link/source" import { UnlinkSourceCommand } from "../../../../src/commands/unlink/source" import { Garden } from "../../../../src/garden" import { LogEntry } from "../../../../src/logger/log-entry" -import * as td from "testdouble" -import { ModuleVersion } from "../../../../src/vcs/vcs" describe("UnlinkCommand", () => { let garden: Garden let log: LogEntry describe("UnlinkModuleCommand", () => { - const projectRoot = getDataDir("test-project-ext-module-sources") const linkCmd = new LinkModuleCommand() const unlinkCmd = new UnlinkModuleCommand() + const linkedModulePathA = join(getDataDir("test-project-local-module-sources"), "module-a") + const linkedModulePathB = join(getDataDir("test-project-local-module-sources"), "module-b") + const linkedModulePathC = join(getDataDir("test-project-local-module-sources"), "module-c") - const dummyVersion: ModuleVersion = { - versionString: "foo", - dependencyVersions: {}, - files: [], - } - - beforeEach(async () => { - garden = await makeTestGarden(projectRoot) + before(async () => { + garden = await makeExtModuleSourcesGarden() log = garden.log - stubExtSources(garden) - - const resolveVersion = td.replace(garden, "resolveVersion") - td.when(resolveVersion("module-a", [])).thenResolve(dummyVersion) - td.when(resolveVersion("module-b", [])).thenResolve(dummyVersion) - td.when(resolveVersion("module-c", [])).thenResolve(dummyVersion) + }) + beforeEach(async () => { await linkCmd.action({ garden, log, @@ -49,7 +39,7 @@ describe("UnlinkCommand", () => { footerLog: log, args: { module: "module-a", - path: join(projectRoot, "mock-local-path", "module-a"), + path: linkedModulePathA, }, opts: withDefaultGlobalOpts({}), }) @@ -60,7 +50,7 @@ describe("UnlinkCommand", () => { footerLog: log, args: { module: "module-b", - path: join(projectRoot, "mock-local-path", "module-b"), + path: linkedModulePathB, }, opts: withDefaultGlobalOpts({}), }) @@ -71,14 +61,14 @@ describe("UnlinkCommand", () => { footerLog: log, args: { module: "module-c", - path: join(projectRoot, "mock-local-path", "module-c"), + path: linkedModulePathC, }, opts: withDefaultGlobalOpts({}), }) }) afterEach(async () => { - await cleanProject(garden.gardenDirPath) + await resetLocalConfig(garden.gardenDirPath) }) it("should unlink the provided modules", async () => { @@ -92,7 +82,7 @@ describe("UnlinkCommand", () => { }) const { linkedModuleSources } = await garden.configStore.get() expect(linkedModuleSources).to.eql([ - { name: "module-c", path: join(projectRoot, "mock-local-path", "module-c") }, + { name: "module-c", path: linkedModulePathC }, ]) }) @@ -111,16 +101,18 @@ describe("UnlinkCommand", () => { }) describe("UnlinkSourceCommand", () => { - const projectRoot = getDataDir("test-project-ext-project-sources") const linkCmd = new LinkSourceCommand() const unlinkCmd = new UnlinkSourceCommand() + const linkedSourcePathA = join(getDataDir("test-project-local-project-sources"), "source-a") + const linkedSourcePathB = join(getDataDir("test-project-local-project-sources"), "source-b") + const linkedSourcePathC = join(getDataDir("test-project-local-project-sources"), "source-c") - beforeEach(async () => { - garden = await makeTestGarden(projectRoot) + before(async () => { + garden = await makeExtProjectSourcesGarden() log = garden.log + }) - stubExtSources(garden) - + beforeEach(async () => { await linkCmd.action({ garden, log, @@ -128,7 +120,7 @@ describe("UnlinkCommand", () => { footerLog: log, args: { source: "source-a", - path: join(projectRoot, "mock-local-path", "source-a"), + path: linkedSourcePathA, }, opts: withDefaultGlobalOpts({}), }) @@ -139,7 +131,7 @@ describe("UnlinkCommand", () => { footerLog: log, args: { source: "source-b", - path: join(projectRoot, "mock-local-path", "source-b"), + path: linkedSourcePathB, }, opts: withDefaultGlobalOpts({}), }) @@ -150,14 +142,14 @@ describe("UnlinkCommand", () => { footerLog: log, args: { source: "source-c", - path: join(projectRoot, "mock-local-path", "source-c"), + path: linkedSourcePathC, }, opts: withDefaultGlobalOpts({}), }) }) afterEach(async () => { - await cleanProject(garden.gardenDirPath) + await resetLocalConfig(garden.gardenDirPath) }) it("should unlink the provided sources", async () => { @@ -171,7 +163,7 @@ describe("UnlinkCommand", () => { }) const { linkedProjectSources } = await garden.configStore.get() expect(linkedProjectSources).to.eql([ - { name: "source-c", path: join(projectRoot, "mock-local-path", "source-c") }, + { name: "source-c", path: linkedSourcePathC }, ]) }) diff --git a/garden-service/test/unit/src/commands/update-remote.ts b/garden-service/test/unit/src/commands/update-remote.ts index a9ab7f2ed14..b57de0b85a7 100644 --- a/garden-service/test/unit/src/commands/update-remote.ts +++ b/garden-service/test/unit/src/commands/update-remote.ts @@ -6,37 +6,36 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import * as td from "testdouble" import { expect } from "chai" import { join } from "path" import { mkdirp, pathExists } from "fs-extra" import { - getDataDir, expectError, - stubExtSources, - makeTestGarden, withDefaultGlobalOpts, + makeExtProjectSourcesGarden, + makeExtModuleSourcesGarden, } from "../../../helpers" import { UpdateRemoteSourcesCommand } from "../../../../src/commands/update-remote/sources" import { UpdateRemoteModulesCommand } from "../../../../src/commands/update-remote/modules" import { Garden } from "../../../../src/garden" import { LogEntry } from "../../../../src/logger/log-entry" -import * as td from "testdouble" -import { ModuleVersion } from "../../../../src/vcs/vcs" describe("UpdateRemoteCommand", () => { describe("UpdateRemoteSourcesCommand", () => { let garden: Garden let log: LogEntry + const cmd = new UpdateRemoteSourcesCommand() - beforeEach(async () => { - garden = await makeTestGarden(projectRoot) + before(async () => { + garden = await makeExtProjectSourcesGarden() log = garden.log - stubExtSources(garden) }) - const projectRoot = getDataDir("test-project-ext-project-sources") - const cmd = new UpdateRemoteSourcesCommand() + beforeEach(async () => { + td.replace(garden.vcs, "updateRemoteSource", async () => undefined) + }) it("should update all project sources", async () => { const { result } = await cmd.action({ @@ -96,26 +95,14 @@ describe("UpdateRemoteCommand", () => { describe("UpdateRemoteModulesCommand", () => { let garden: Garden let log: LogEntry - - const dummyVersion: ModuleVersion = { - versionString: "foo", - dependencyVersions: {}, - files: [], - } + const cmd = new UpdateRemoteModulesCommand() beforeEach(async () => { - garden = await makeTestGarden(projectRoot) + garden = await makeExtModuleSourcesGarden() + td.replace(garden.vcs, "updateRemoteSource", async () => undefined) log = garden.log - stubExtSources(garden) - const resolveVersion = td.replace(garden, "resolveVersion") - td.when(resolveVersion("module-a", [])).thenResolve(dummyVersion) - td.when(resolveVersion("module-b", [])).thenResolve(dummyVersion) - td.when(resolveVersion("module-c", [])).thenResolve(dummyVersion) }) - const projectRoot = getDataDir("test-project-ext-module-sources") - const cmd = new UpdateRemoteModulesCommand() - it("should update all modules sources", async () => { const { result } = await cmd.action({ garden, diff --git a/garden-service/test/unit/src/garden.ts b/garden-service/test/unit/src/garden.ts index b7db7036236..7a5674f408a 100644 --- a/garden-service/test/unit/src/garden.ts +++ b/garden-service/test/unit/src/garden.ts @@ -8,18 +8,20 @@ import { makeTestGarden, makeTestGardenA, projectRootA, - stubExtSources, getDataDir, - cleanProject, testModuleVersion, TestGarden, testPlugin, + makeExtProjectSourcesGarden, + makeExtModuleSourcesGarden, + testGitUrlHash, + resetLocalConfig, + testGitUrl, } from "../../helpers" import { getNames } from "../../../src/util/util" import { MOCK_CONFIG } from "../../../src/cli/cli" import { LinkedSource } from "../../../src/config-store" import { ModuleVersion } from "../../../src/vcs/vcs" -import { hashRepoUrl } from "../../../src/util/ext-source-util" import { getModuleCacheContext } from "../../../src/types/module" import { Plugins, GardenPlugin, PluginFactory } from "../../../src/types/plugin/plugin" import { ConfigureProviderParams } from "../../../src/types/plugin/provider/configureProvider" @@ -723,22 +725,8 @@ describe("Garden", () => { }) it("should scan and add modules for projects with external project sources", async () => { - const garden = await makeTestGarden(resolve(dataDir, "test-project-ext-project-sources"), { - gardenDirPath: "mock-dot-garden", - }) - - const getRemoteSourceRelPath = td.replace(garden.vcs, "getRemoteSourceRelPath") - td.when(getRemoteSourceRelPath("source-a"), { ignoreExtraArgs: true }) - .thenReturn(join("sources", "project", "source-a")) - td.when(getRemoteSourceRelPath("source-b"), { ignoreExtraArgs: true }) - .thenReturn(join("sources", "project", "source-b")) - td.when(getRemoteSourceRelPath("source-c"), { ignoreExtraArgs: true }) - .thenReturn(join("sources", "project", "source-c")) - - stubExtSources(garden) - + const garden = await makeExtProjectSourcesGarden() await garden.scanModules() - const modules = await garden.resolveModuleConfigs() expect(getNames(modules).sort()).to.eql(["module-a", "module-b", "module-c"]) }) @@ -817,13 +805,11 @@ describe("Garden", () => { it("should resolve module path to external sources dir if module has a remote source", async () => { const projectRoot = resolve(dataDir, "test-project-ext-module-sources") - const garden = await makeTestGarden(projectRoot) - stubExtSources(garden) + const garden = await makeExtModuleSourcesGarden() const module = await garden.resolveModuleConfig("module-a") - const repoUrlHash = hashRepoUrl(module!.repositoryUrl!) - expect(module!.path).to.equal(join(projectRoot, ".garden", "sources", "module", `module-a--${repoUrlHash}`)) + expect(module!.path).to.equal(join(projectRoot, ".garden", "sources", "module", `module-a--${testGitUrlHash}`)) }) it.skip("should set default values properly", async () => { @@ -906,74 +892,82 @@ describe("Garden", () => { describe("loadExtSourcePath", () => { let garden: TestGarden - const makeGarden = async (root) => { - garden = await makeTestGarden(root) - stubExtSources(garden) - return garden - } + context("external project sources", () => { + before(async () => { + garden = await makeExtProjectSourcesGarden() + }) - afterEach(async () => { - if (garden) { - await cleanProject(garden.gardenDirPath) - } - }) + afterEach(async () => { + await resetLocalConfig(garden.gardenDirPath) + }) - it("should return the path to the project source if source type is project", async () => { - const projectRoot = getDataDir("test-project-ext-project-sources") - garden = await makeGarden(projectRoot) - const repositoryUrl = "https://github.com/org/repo.git#master" - const path = await garden.loadExtSourcePath({ repositoryUrl, name: "source-a", sourceType: "project" }) - const repoUrlHash = hashRepoUrl(repositoryUrl) - expect(path).to.equal(join(projectRoot, ".garden", "sources", "project", `source-a--${repoUrlHash}`)) - }) + it("should return the path to the project source if source type is project", async () => { + const projectRoot = getDataDir("test-project-ext-project-sources") + const path = await garden.loadExtSourcePath({ + repositoryUrl: testGitUrl, + name: "source-a", + sourceType: "project", + }) + expect(path).to.equal(join(projectRoot, ".garden", "sources", "project", `source-a--${testGitUrlHash}`)) + }) - it("should return the path to the module source if source type is module", async () => { - const projectRoot = getDataDir("test-project-ext-module-sources") - garden = await makeGarden(projectRoot) - const repositoryUrl = "https://github.com/org/repo.git#master" - const path = await garden.loadExtSourcePath({ repositoryUrl, name: "module-a", sourceType: "module" }) - const repoUrlHash = hashRepoUrl(repositoryUrl) - expect(path).to.equal(join(projectRoot, ".garden", "sources", "module", `module-a--${repoUrlHash}`)) - }) + it("should return the local path of the project source if linked", async () => { + const localProjectSourceDir = getDataDir("test-project-local-project-sources") + const linkedSourcePath = join(localProjectSourceDir, "source-a") - it("should return the local path of the project source if linked", async () => { - const projectRoot = getDataDir("test-project-ext-project-sources") - garden = await makeGarden(projectRoot) - const localPath = join(projectRoot, "mock-local-path", "source-a") + const linked: LinkedSource[] = [{ + name: "source-a", + path: linkedSourcePath, + }] + await garden.configStore.set(["linkedProjectSources"], linked) - const linked: LinkedSource[] = [{ - name: "source-a", - path: localPath, - }] - await garden.configStore.set(["linkedProjectSources"], linked) + const path = await garden.loadExtSourcePath({ + name: "source-a", + repositoryUrl: testGitUrl, + sourceType: "project", + }) - const path = await garden.loadExtSourcePath({ - name: "source-a", - repositoryUrl: "https://github.com/org/repo.git#master", - sourceType: "project", + expect(path).to.equal(linkedSourcePath) }) - - expect(path).to.equal(join(projectRoot, "mock-local-path", "source-a")) }) - it("should return the local path of the module source if linked", async () => { - const projectRoot = getDataDir("test-project-ext-module-sources") - garden = await makeGarden(projectRoot) - const localPath = join(projectRoot, "mock-local-path", "module-a") + context("external module sources", () => { + before(async () => { + garden = await makeExtModuleSourcesGarden() + }) - const linked: LinkedSource[] = [{ - name: "module-a", - path: localPath, - }] - await garden.configStore.set(["linkedModuleSources"], linked) + afterEach(async () => { + await resetLocalConfig(garden.gardenDirPath) + }) - const path = await garden.loadExtSourcePath({ - name: "module-a", - repositoryUrl: "https://github.com/org/repo.git#master", - sourceType: "module", + it("should return the path to the module source if source type is module", async () => { + const projectRoot = getDataDir("test-project-ext-module-sources") + const path = await garden.loadExtSourcePath({ + repositoryUrl: testGitUrl, + name: "module-a", + sourceType: "module", + }) + expect(path).to.equal(join(projectRoot, ".garden", "sources", "module", `module-a--${testGitUrlHash}`)) }) - expect(path).to.equal(join(projectRoot, "mock-local-path", "module-a")) + it("should return the local path of the module source if linked", async () => { + const localModuleSourceDir = getDataDir("test-project-local-module-sources") + const linkedModulePath = join(localModuleSourceDir, "module-a") + + const linked: LinkedSource[] = [{ + name: "module-a", + path: linkedModulePath, + }] + await garden.configStore.set(["linkedModuleSources"], linked) + + const path = await garden.loadExtSourcePath({ + name: "module-a", + repositoryUrl: testGitUrl, + sourceType: "module", + }) + + expect(path).to.equal(linkedModulePath) + }) }) }) }) diff --git a/garden-service/test/unit/src/util/ext-source-util.ts b/garden-service/test/unit/src/util/ext-source-util.ts index 7b7b033fb15..88ae71950b3 100644 --- a/garden-service/test/unit/src/util/ext-source-util.ts +++ b/garden-service/test/unit/src/util/ext-source-util.ts @@ -8,7 +8,7 @@ import { getRemoteSourceRelPath, hashRepoUrl, } from "../../../../src/util/ext-source-util" -import { cleanProject, expectError, makeTestGardenA } from "../../../helpers" +import { expectError, makeTestGardenA } from "../../../helpers" import { Garden } from "../../../../src/garden" import { join } from "path" @@ -20,10 +20,6 @@ describe("ext-source-util", () => { garden = await makeTestGardenA() }) - afterEach(async () => { - await cleanProject(garden.gardenDirPath) - }) - describe("getExtSourcesDirName", () => { it("should return the relative path to the remote projects directory", () => { const dirName = getRemoteSourcesDirname("project") diff --git a/garden-service/test/unit/src/watch.ts b/garden-service/test/unit/src/watch.ts index 4cac7b8d083..5c3a13f8541 100644 --- a/garden-service/test/unit/src/watch.ts +++ b/garden-service/test/unit/src/watch.ts @@ -1,10 +1,27 @@ import { resolve, join } from "path" -import { TestGarden, dataDir, makeTestGarden } from "../../helpers" import { expect } from "chai" -import { CacheContext, pathToCacheContext } from "../../../src/cache" import pEvent = require("p-event") + +import { + TestGarden, + dataDir, + makeTestGarden, + withDefaultGlobalOpts, + makeExtModuleSourcesGarden, + resetLocalConfig, + makeExtProjectSourcesGarden, +} from "../../helpers" +import { CacheContext, pathToCacheContext } from "../../../src/cache" import { createFile, remove, pathExists } from "fs-extra" import { getConfigFilePath } from "../../../src/util/fs" +import { LinkModuleCommand } from "../../../src/commands/link/module" +import { cleanUpGlobalWatcher } from "../../../src/watch" +import { LinkSourceCommand } from "../../../src/commands/link/source" +import { sleep } from "../../../src/util/util" + +function emitEvent(garden: TestGarden, name: string, payload: any) { + garden["watcher"]["watcher"].emit(name, payload) +} describe("Watcher", () => { let garden: TestGarden @@ -30,17 +47,13 @@ describe("Watcher", () => { await garden.close() }) - function emitEvent(name: string, payload: any) { - (garden).watcher.watcher.emit(name, payload) - } - async function waitForEvent(name: string) { return pEvent(garden.events, name, { timeout: 2000 }) } it("should emit a moduleConfigChanged changed event when module config is changed", async () => { const path = await getConfigFilePath(modulePath) - emitEvent("change", path) + emitEvent(garden, "change", path) expect(garden.events.eventLog).to.eql([ { name: "moduleConfigChanged", payload: { names: ["module-a"], path } }, ]) @@ -48,7 +61,7 @@ describe("Watcher", () => { it("should emit a moduleConfigChanged event when module config is changed and include field is set", async () => { const path = await getConfigFilePath(includeModulePath) - emitEvent("change", path) + emitEvent(garden, "change", path) expect(garden.events.eventLog).to.eql([ { name: "moduleConfigChanged", payload: { names: ["with-include"], path } }, ]) @@ -56,13 +69,13 @@ describe("Watcher", () => { it("should clear all module caches when a module config is changed", async () => { const path = await getConfigFilePath(modulePath) - emitEvent("change", path) + emitEvent(garden, "change", path) expect(garden.cache.getByContext(moduleContext)).to.eql(new Map()) }) it("should emit a projectConfigChanged changed event when project config is changed", async () => { const path = await getConfigFilePath(garden.projectRoot) - emitEvent("change", path) + emitEvent(garden, "change", path) expect(garden.events.eventLog).to.eql([ { name: "projectConfigChanged", payload: {} }, ]) @@ -70,7 +83,7 @@ describe("Watcher", () => { it("should emit a projectConfigChanged changed event when project config is removed", async () => { const path = await getConfigFilePath(garden.projectRoot) - emitEvent("unlink", path) + emitEvent(garden, "unlink", path) expect(garden.events.eventLog).to.eql([ { name: "projectConfigChanged", payload: {} }, ]) @@ -78,7 +91,7 @@ describe("Watcher", () => { it("should emit a projectConfigChanged changed event when ignore files are changed", async () => { const path = join(await getConfigFilePath(garden.projectRoot), ".gardenignore") - emitEvent("change", path) + emitEvent(garden, "change", path) expect(garden.events.eventLog).to.eql([ { name: "projectConfigChanged", payload: {} }, ]) @@ -86,19 +99,19 @@ describe("Watcher", () => { it("should clear all module caches when project config is changed", async () => { const path = await getConfigFilePath(garden.projectRoot) - emitEvent("change", path) + emitEvent(garden, "change", path) expect(garden.cache.getByContext(moduleContext)).to.eql(new Map()) }) it("should emit a configAdded event when adding a garden.yml file", async () => { const path = await getConfigFilePath(join(garden.projectRoot, "module-b")) - emitEvent("add", path) + emitEvent(garden, "add", path) expect(await waitForEvent("configAdded")).to.eql({ path }) }) it("should emit a configRemoved event when removing a garden.yml file", async () => { const path = await getConfigFilePath(join(garden.projectRoot, "module-b")) - emitEvent("unlink", path) + emitEvent(garden, "unlink", path) expect(garden.events.eventLog).to.eql([ { name: "configRemoved", payload: { path } }, ]) @@ -107,7 +120,7 @@ describe("Watcher", () => { context("should emit a moduleSourcesChanged event", () => { it("containing the module's name when one of its files is changed", async () => { const pathChanged = resolve(modulePath, "foo.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.events.eventLog).to.eql([ { name: "moduleSourcesChanged", payload: { names: ["module-a"], pathChanged } }, ]) @@ -115,7 +128,7 @@ describe("Watcher", () => { it("if a file is changed and it matches a module's include list", async () => { const pathChanged = resolve(includeModulePath, "subdir", "foo2.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.events.eventLog).to.eql([ { name: "moduleSourcesChanged", payload: { names: ["with-include"], pathChanged } }, ]) @@ -133,7 +146,7 @@ describe("Watcher", () => { it("containing both modules' names when a source file is changed for two co-located modules", async () => { const pathChanged = resolve(doubleModulePath, "foo.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.events.eventLog).to.eql([ { name: "moduleSourcesChanged", payload: { names: ["module-b", "module-c"], pathChanged } }, ]) @@ -142,30 +155,30 @@ describe("Watcher", () => { it("should not emit moduleSourcesChanged if file is changed and doesn't match module's include list", async () => { const pathChanged = resolve(includeModulePath, "foo.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.events.eventLog).to.eql([]) }) it("should not emit moduleSourcesChanged if file is changed and it's in a gardenignore in the module", async () => { const pathChanged = resolve(modulePath, "module-excluded.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.events.eventLog).to.eql([]) }) it("should not emit moduleSourcesChanged if file is changed and it's in a gardenignore in the project", async () => { const pathChanged = resolve(modulePath, "project-excluded.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.events.eventLog).to.eql([]) }) it("should clear a module's cache when a module file is changed", async () => { const pathChanged = resolve(modulePath, "foo.txt") - emitEvent("change", pathChanged) + emitEvent(garden, "change", pathChanged) expect(garden.cache.getByContext(moduleContext)).to.eql(new Map()) }) it("should emit a configAdded event when a directory is added that contains a garden.yml file", async () => { - emitEvent("addDir", modulePath) + emitEvent(garden, "addDir", modulePath) expect(await waitForEvent("configAdded")).to.eql({ path: await getConfigFilePath(modulePath), }) @@ -173,7 +186,7 @@ describe("Watcher", () => { it("should emit a moduleSourcesChanged event when a directory is added under a module directory", async () => { const pathChanged = resolve(modulePath, "subdir") - emitEvent("addDir", pathChanged) + emitEvent(garden, "addDir", pathChanged) expect(await waitForEvent("moduleSourcesChanged")).to.eql({ names: ["module-a"], pathChanged, @@ -182,13 +195,13 @@ describe("Watcher", () => { it("should clear a module's cache when a directory is added under a module directory", async () => { const pathChanged = resolve(modulePath, "subdir") - emitEvent("addDir", pathChanged) + emitEvent(garden, "addDir", pathChanged) await waitForEvent("moduleSourcesChanged") expect(garden.cache.getByContext(moduleContext)).to.eql(new Map()) }) it("should emit a moduleRemoved event if a directory containing a module is removed", async () => { - emitEvent("unlinkDir", modulePath) + emitEvent(garden, "unlinkDir", modulePath) expect(garden.events.eventLog).to.eql([ { name: "moduleRemoved", payload: {} }, ]) @@ -196,9 +209,148 @@ describe("Watcher", () => { it("should emit a moduleSourcesChanged event if a directory within a module is removed", async () => { const pathChanged = resolve(modulePath, "subdir") - emitEvent("unlinkDir", pathChanged) + emitEvent(garden, "unlinkDir", pathChanged) expect(garden.events.eventLog).to.eql([ { name: "moduleSourcesChanged", payload: { names: ["module-a"], pathChanged } }, ]) }) + + context("linked module sources", () => { + const localModuleSourceDir = resolve(dataDir, "test-project-local-module-sources") + const localModulePathA = join(localModuleSourceDir, "module-a") + const localModulePathB = join(localModuleSourceDir, "module-b") + + before(async () => { + // The watcher instance is global so we clean up the previous one before proceeding + cleanUpGlobalWatcher() + garden = await makeExtModuleSourcesGarden() + + // Link some modules + const linkCmd = new LinkModuleCommand() + await linkCmd.action({ + garden, + log: garden.log, + headerLog: garden.log, + footerLog: garden.log, + args: { + module: "module-a", + path: localModulePathA, + }, + opts: withDefaultGlobalOpts({}), + }) + await linkCmd.action({ + garden, + log: garden.log, + headerLog: garden.log, + footerLog: garden.log, + args: { + module: "module-b", + path: localModulePathB, + }, + opts: withDefaultGlobalOpts({}), + }) + + // We need to make a new instance of Garden after linking the sources + // This is not an issue in practice because there are specific commands just for linking + // so the user will always have a new instance of Garden when they run their next command. + garden = await makeExtModuleSourcesGarden() + await garden.startWatcher(await garden.getConfigGraph()) + // This ensures that the watcher is properly initialised when we call `watcher.getWatched()` below + await sleep(100) + }) + + beforeEach(() => { + garden.events.clearLog() + }) + + after(async () => { + await resetLocalConfig(garden.gardenDirPath) + await garden.close() + }) + + it("should watch all linked repositories", () => { + const watcher = garden["watcher"]["watcher"] + const shouldWatch = [garden.projectRoot, localModulePathA, localModulePathB] + const watched = Object.keys(watcher.getWatched()) + expect(shouldWatch.every(path => watched.includes(path))).to.be.true + }) + + it("should emit a moduleSourcesChanged event when a linked module source is changed", async () => { + const pathChanged = resolve(localModuleSourceDir, "module-a", "foo.txt") + emitEvent(garden, "change", pathChanged) + expect(garden.events.eventLog).to.eql([ + { name: "moduleSourcesChanged", payload: { names: ["module-a"], pathChanged } }, + ]) + }) + }) + + context("linked project sources", () => { + const localProjectSourceDir = resolve(dataDir, "test-project-local-project-sources") + const localSourcePathA = join(localProjectSourceDir, "source-a") + const localSourcePathB = join(localProjectSourceDir, "source-b") + + before(async () => { + // The watcher instance is global so we clean up the previous one before proceeding + cleanUpGlobalWatcher() + garden = await makeExtProjectSourcesGarden() + + // Link some projects + const linkCmd = new LinkSourceCommand() + await linkCmd.action({ + garden, + log: garden.log, + headerLog: garden.log, + footerLog: garden.log, + args: { + source: "source-a", + path: localSourcePathA, + }, + opts: withDefaultGlobalOpts({}), + }) + await linkCmd.action({ + garden, + log: garden.log, + headerLog: garden.log, + footerLog: garden.log, + args: { + source: "source-b", + path: localSourcePathB, + }, + opts: withDefaultGlobalOpts({}), + }) + + // We need to make a new instance of Garden after linking the sources + // This is not an issue in practice because there are specific commands just for linking + // so the user will always have a new instance of Garden when they run their next command. + garden = await makeExtProjectSourcesGarden() + await garden.startWatcher(await garden.getConfigGraph()) + // This ensures that the watcher is properly initialised when we call `watcher.getWatched()` below + await sleep(100) + }) + + beforeEach(() => { + garden.events.clearLog() + }) + + after(async () => { + await resetLocalConfig(garden.gardenDirPath) + await garden.close() + }) + + it("should watch all linked repositories", () => { + const watcher = garden["watcher"]["watcher"] + const shouldWatch = [garden.projectRoot, localSourcePathA, localSourcePathB] + const watched = Object.keys(watcher.getWatched()) + expect(shouldWatch.every(path => watched.includes(path))).to.be.true + }) + + it("should emit a moduleSourcesChanged event when a linked project source is changed", async () => { + const pathChanged = resolve(localProjectSourceDir, "source-a", "module-a", "foo.txt") + emitEvent(garden, "change", pathChanged) + expect(garden.events.eventLog).to.eql([ + { name: "moduleSourcesChanged", payload: { names: ["module-a"], pathChanged } }, + ]) + }) + }) + })