mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
push/build: Add test cases for .dockerignore filtering corner cases
Change-type: patch
This commit is contained in:
parent
55fc9b2ade
commit
d64b6deb81
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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<string>((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<void>((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<void>((resolve, reject) => {
|
||||
server.close((e) => (e ? reject(e) : resolve()));
|
||||
});
|
||||
|
||||
expect(await exists(socketPath), 'Socket existence').to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('balena push: project validation', function () {
|
||||
|
@ -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<string> {
|
||||
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] ---------------------------------------------------------------------------`,
|
||||
];
|
||||
}
|
||||
|
@ -1 +1,2 @@
|
||||
service1/test-ignore*
|
||||
**/.dockerignore
|
||||
|
Loading…
Reference in New Issue
Block a user