diff --git a/tests/commands/build.spec.ts b/tests/commands/build.spec.ts index 1288d59c..7bd709b1 100644 --- a/tests/commands/build.spec.ts +++ b/tests/commands/build.spec.ts @@ -32,6 +32,7 @@ import { ExpectedTarStreamFilesByService, getDockerignoreWarn1, getDockerignoreWarn2, + getDockerignoreWarn3, } from '../projects'; const repoPath = path.normalize(path.join(__dirname, '..', '..')); @@ -184,6 +185,10 @@ describe('balena build', function () { `[Info] No "docker-compose.yml" file found at "${projectPath}"`, `[Info] Creating default composition with source: "${projectPath}"`, '[Build] main Step 1/4 : FROM busybox', + ...getDockerignoreWarn1( + [path.join(projectPath, 'src', '.dockerignore')], + 'build', + ), ]; if (isWindows) { const fname = path.join(projectPath, 'src', 'windows-crlf.sh'); @@ -383,7 +388,6 @@ describe('balena build', function () { 'file1.sh': { fileSize: 12, type: 'file' }, }, service2: { - '.dockerignore': { fileSize: 12, type: 'file' }, 'Dockerfile-alt': { fileSize: 13, type: 'file' }, 'file2-crlf.sh': { fileSize: isWindows ? 12 : 14, @@ -513,13 +517,7 @@ describe('balena build', function () { '[Build] service1 Step 1/4 : FROM busybox', '[Build] service2 Step 1/4 : FROM busybox', ], - ...[ - `[Info] ---------------------------------------------------------------------------`, - '[Info] The --multi-dockerignore option is being used, and a .dockerignore file was', - '[Info] found at the project source (root) directory. Note that this file will not', - '[Info] be used to filter service subdirectories. See "balena help build".', - `[Info] ---------------------------------------------------------------------------`, - ], + ...getDockerignoreWarn3('build'), ]; if (isWindows) { expectedResponseLines.push( @@ -602,13 +600,7 @@ describe('balena build', function () { '[Build] service1 Step 1/4 : FROM busybox', '[Build] service2 Step 1/4 : FROM busybox', ], - ...[ - `[Info] ---------------------------------------------------------------------------`, - '[Info] The --multi-dockerignore option is being used, and a .dockerignore file was', - '[Info] found at the project source (root) directory. Note that this file will not', - '[Info] be used to filter service subdirectories. See "balena help build".', - `[Info] ---------------------------------------------------------------------------`, - ], + ...getDockerignoreWarn3('build'), ]; if (isWindows) { expectedResponseLines.push( diff --git a/tests/commands/deploy.spec.ts b/tests/commands/deploy.spec.ts index dc6e22b7..2067b318 100644 --- a/tests/commands/deploy.spec.ts +++ b/tests/commands/deploy.spec.ts @@ -32,6 +32,7 @@ import { ExpectedTarStreamFiles, ExpectedTarStreamFilesByService, getDockerignoreWarn1, + getDockerignoreWarn3, } from '../projects'; const repoPath = path.normalize(path.join(__dirname, '..', '..')); @@ -396,13 +397,7 @@ describe('balena deploy', function () { '[Build] service1 Step 1/4 : FROM busybox', '[Build] service2 Step 1/4 : FROM busybox', ], - ...[ - `[Info] ---------------------------------------------------------------------------`, - '[Info] The --multi-dockerignore option is being used, and a .dockerignore file was', - '[Info] found at the project source (root) directory. Note that this file will not', - '[Info] be used to filter service subdirectories. See "balena help deploy".', - `[Info] ---------------------------------------------------------------------------`, - ], + ...getDockerignoreWarn3('deploy'), ]; if (isWindows) { expectedResponseLines.push( diff --git a/tests/commands/push.spec.ts b/tests/commands/push.spec.ts index 4cd0e976..c13d1370 100644 --- a/tests/commands/push.spec.ts +++ b/tests/commands/push.spec.ts @@ -26,9 +26,11 @@ import { expectStreamNoCRLF, testPushBuildStream } from '../docker-build'; import { cleanOutput, runCommand } from '../helpers'; import { addRegSecretsEntries, + exists, ExpectedTarStreamFiles, getDockerignoreWarn1, getDockerignoreWarn2, + getDockerignoreWarn3, setupDockerignoreTestData, } from '../projects'; @@ -36,6 +38,7 @@ const repoPath = path.normalize(path.join(__dirname, '..', '..')); const projectsPath = path.join(repoPath, 'tests', 'test-data', 'projects'); const itNoV13 = isV13() ? it.skip : it; +const itNoWin = process.platform === 'win32' ? it.skip : it; const commonResponseLines = { 'build-POST-v3.json': [ @@ -451,12 +454,10 @@ describe('balena push', function () { const projectPath = path.join(projectsPath, 'docker-compose', 'basic'); const expectedFiles: ExpectedTarStreamFiles = { '.balena/balena.yml': { fileSize: 197, type: 'file' }, - '.dockerignore': { fileSize: 22, type: 'file' }, 'docker-compose.yml': { fileSize: 332, type: 'file' }, 'service1/Dockerfile.template': { fileSize: 144, type: 'file' }, 'service1/file1.sh': { fileSize: 12, type: 'file' }, 'service2/Dockerfile-alt': { fileSize: 13, type: 'file' }, - 'service2/.dockerignore': { fileSize: 12, type: 'file' }, 'service2/file2-crlf.sh': { fileSize: isWindows ? 12 : 14, testStream: isWindows ? expectStreamNoCRLF : undefined, @@ -503,7 +504,6 @@ describe('balena push', function () { const projectPath = path.join(projectsPath, 'docker-compose', 'basic'); const expectedFiles: ExpectedTarStreamFiles = { '.balena/balena.yml': { fileSize: 197, type: 'file' }, - '.dockerignore': { fileSize: 22, type: 'file' }, 'docker-compose.yml': { fileSize: 332, type: 'file' }, 'service1/Dockerfile.template': { fileSize: 144, type: 'file' }, 'service1/file1.sh': { fileSize: 12, type: 'file' }, @@ -524,13 +524,7 @@ describe('balena push', function () { ); const expectedResponseLines: string[] = [ ...commonResponseLines[responseFilename], - ...[ - `[Info] ---------------------------------------------------------------------------`, - '[Info] The --multi-dockerignore option is being used, and a .dockerignore file was', - '[Info] found at the project source (root) directory. Note that this file will not', - '[Info] be used to filter service subdirectories. See "balena help push".', - `[Info] ---------------------------------------------------------------------------`, - ], + ...getDockerignoreWarn3('push'), ]; if (isWindows) { expectedResponseLines.push( @@ -553,6 +547,66 @@ describe('balena push', function () { responseCode: 200, }); }); + + // Skip on Windows because this test uses Unix domain sockets + itNoWin('should create the expected tar stream (socket file)', async () => { + // This test creates project files dynamically in a temp dir, where + // a Unix domain socket file is created and listened on. A specific + // reason use use a temp dir is that Unix domain socket paths are + // limited in length to just over 100 characters, while the project + // paths in the test-data folder easily exceed that limit. + const tmp = await import('tmp'); + tmp.setGracefulCleanup(); + const projectPath = await new Promise((resolve, reject) => { + const opts = { template: 'tmp-XXXXXX', unsafeCleanup: true }; + tmp.dir(opts, (e, p) => (e ? reject(e) : resolve(p))); + }); + console.error(`[debug] Temp project dir: ${projectPath}`); + + // Create a Unix Domain Socket file that should not be included in the tar stream + const net = await import('net'); + const server = net.createServer(); + const socketPath = path.join(projectPath, 'socket'); + await new Promise((resolve, reject) => { + server.on('error', reject); + try { + server.listen(socketPath, resolve); + } catch (e) { + reject(e); + } + }); + console.error(`[debug] Checking existence of socket at '${socketPath}'`); + expect(await exists(socketPath), 'Socket existence').to.be.true; + + await fs.writeFile(path.join(projectPath, 'Dockerfile'), 'FROM busybox\n'); + + const expectedFiles: ExpectedTarStreamFiles = { + Dockerfile: { fileSize: 13, type: 'file' }, + }; + const responseFilename = 'build-POST-v3.json'; + const responseBody = await fs.readFile( + path.join(builderResponsePath, responseFilename), + 'utf8', + ); + + await testPushBuildStream({ + builderMock: builder, + commandLine: `push testApp -s ${projectPath}`, + expectedFiles, + expectedQueryParams: commonQueryParams, + expectedResponseLines: commonResponseLines[responseFilename], + projectPath, + responseBody, + responseCode: 200, + }); + + // Terminate Unix Domain Socket server + await new Promise((resolve, reject) => { + server.close((e) => (e ? reject(e) : resolve())); + }); + + expect(await exists(socketPath), 'Socket existence').to.be.false; + }); }); describe('balena push: project validation', function () { diff --git a/tests/projects.ts b/tests/projects.ts index ef9f0c73..b842ccce 100644 --- a/tests/projects.ts +++ b/tests/projects.ts @@ -15,12 +15,9 @@ * limitations under the License. */ -import * as fs from 'fs'; +import { promises as fs } from 'fs'; import * as path from 'path'; import type { Headers } from 'tar-stream'; -import { promisify } from 'util'; - -const statAsync = promisify(fs.stat); export interface ExpectedTarStreamFile { contents?: string; @@ -49,6 +46,15 @@ export const projectsPath = path.join( 'projects', ); +export async function exists(fPath: string) { + try { + await fs.stat(fPath); + return true; + } catch (e) { + return false; + } +} + export async function setupDockerignoreTestData({ cleanup = false } = {}) { const { copy, remove } = await import('fs-extra'); const dockerignoreProjDir = path.join( @@ -78,7 +84,7 @@ export async function addRegSecretsEntries( ): Promise { const regSecretsPath = path.join(projectsPath, 'registry-secrets.json'); expectedFiles['.balena/registry-secrets.json'] = { - fileSize: (await statAsync(regSecretsPath)).size, + fileSize: (await fs.stat(regSecretsPath)).size, type: 'file', }; return regSecretsPath; @@ -115,3 +121,13 @@ export function getDockerignoreWarn2(paths: string[], cmd: string) { ); return lines; } + +export function getDockerignoreWarn3(cmd: string) { + return [ + `[Info] ---------------------------------------------------------------------------`, + '[Info] The --multi-dockerignore option is being used, and a .dockerignore file was', + '[Info] found at the project source (root) directory. Note that this file will not', + `[Info] be used to filter service subdirectories. See "balena help ${cmd}".`, + `[Info] ---------------------------------------------------------------------------`, + ]; +} diff --git a/tests/test-data/projects/docker-compose/basic/.dockerignore b/tests/test-data/projects/docker-compose/basic/.dockerignore index 9a30e714..e4956685 100644 --- a/tests/test-data/projects/docker-compose/basic/.dockerignore +++ b/tests/test-data/projects/docker-compose/basic/.dockerignore @@ -1 +1,2 @@ service1/test-ignore* +**/.dockerignore