mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2024-12-24 15:56:40 +00:00
Merge pull request #1505 from balena-io/1492-compose-image-tests
Add more test coverage for compose/images
This commit is contained in:
commit
064d8f1562
@ -6,9 +6,6 @@ process.env.DATABASE_PATH_2 = './test/data/database2.sqlite';
|
||||
process.env.DATABASE_PATH_3 = './test/data/database3.sqlite';
|
||||
process.env.LED_FILE = './test/data/led_file';
|
||||
|
||||
import * as dbus from 'dbus';
|
||||
import { DBusError, DBusInterface } from 'dbus';
|
||||
import { stub } from 'sinon';
|
||||
import * as fs from 'fs';
|
||||
|
||||
// Make sure they are no database files left over from
|
||||
@ -33,31 +30,7 @@ fs.writeFileSync(
|
||||
fs.readFileSync('./test/data/testconfig.json'),
|
||||
);
|
||||
|
||||
stub(dbus, 'getBus').returns({
|
||||
getInterface: (
|
||||
_serviceName: string,
|
||||
_objectPath: string,
|
||||
_interfaceName: string,
|
||||
interfaceCb: (err: null | DBusError, iface: DBusInterface) => void,
|
||||
) => {
|
||||
interfaceCb(null, {
|
||||
Get: (
|
||||
_unitName: string,
|
||||
_property: string,
|
||||
getCb: (err: null | Error, value: unknown) => void,
|
||||
) => {
|
||||
getCb(null, 'this is the value');
|
||||
},
|
||||
GetUnit: (
|
||||
_unitName: string,
|
||||
getUnitCb: (err: null | Error, unitPath: string) => void,
|
||||
) => {
|
||||
getUnitCb(null, 'this is the unit path');
|
||||
},
|
||||
} as any);
|
||||
},
|
||||
} as any);
|
||||
|
||||
import './lib/mocked-dbus';
|
||||
import './lib/mocked-dockerode';
|
||||
import './lib/mocked-iptables';
|
||||
import './lib/mocked-event-tracker';
|
||||
|
133
test/39-compose-images.spec.ts
Normal file
133
test/39-compose-images.spec.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { docker } from '../src/lib/docker-utils';
|
||||
import { expect } from './lib/chai-config';
|
||||
import * as Images from '../src/compose/images';
|
||||
import * as mockedDockerode from './lib/mocked-dockerode';
|
||||
import * as mockedDatabase from './lib/mocked-database';
|
||||
import * as db from '../src/db';
|
||||
import * as sampleImageData from './data/compose-image-data.json';
|
||||
|
||||
describe('compose/images', () => {
|
||||
before(() => {
|
||||
mockedDatabase.create();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
try {
|
||||
mockedDatabase.restore();
|
||||
} catch (e) {
|
||||
/* noop */
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clear Dockerode actions recorded for each test
|
||||
mockedDockerode.resetHistory();
|
||||
});
|
||||
|
||||
it('Removes a legacy Image', async () => {
|
||||
const images = sampleImageData['legacy-image'].dockerode;
|
||||
const IMAGE_TO_REMOVE = sampleImageData['legacy-image'].remove;
|
||||
const IMAGES_FROM_DB = sampleImageData['legacy-image'].database;
|
||||
// Stub the database to return images we want
|
||||
mockedDatabase.setImages(IMAGES_FROM_DB).stub();
|
||||
// Perform the test with our specially crafted data
|
||||
await mockedDockerode.testWithData({ images }, async () => {
|
||||
// Check that our legacy image exists
|
||||
await expect(docker.getImage(IMAGE_TO_REMOVE.name).inspect()).to
|
||||
.eventually.not.be.undefined;
|
||||
await expect(
|
||||
db.models('image').select().where(IMAGE_TO_REMOVE),
|
||||
).to.eventually.have.lengthOf(1);
|
||||
// Check that docker has this Image
|
||||
await expect(docker.getImage(IMAGE_TO_REMOVE.name).inspect()).to
|
||||
.eventually.not.be.undefined;
|
||||
// Now remove this image...
|
||||
await Images.remove(IMAGE_TO_REMOVE);
|
||||
// Check if it still exists!
|
||||
await expect(docker.getImage(IMAGE_TO_REMOVE.name).inspect()).to
|
||||
.eventually.be.undefined;
|
||||
await expect(db.models('image').select().where(IMAGE_TO_REMOVE)).to
|
||||
.eventually.be.empty;
|
||||
// Check that docker remove was called once
|
||||
const removeSteps = _(mockedDockerode.actions)
|
||||
.pickBy({ name: 'remove' })
|
||||
.map()
|
||||
.value();
|
||||
expect(removeSteps).to.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('Removes a single Image', async () => {
|
||||
const images = sampleImageData['single-image'].dockerode;
|
||||
const IMAGE_TO_REMOVE = sampleImageData['single-image'].remove;
|
||||
const IMAGES_FROM_DB = sampleImageData['single-image'].database;
|
||||
// Stub the database to return images we want
|
||||
mockedDatabase.setImages(IMAGES_FROM_DB).stub();
|
||||
// Perform the test with our specially crafted data
|
||||
await mockedDockerode.testWithData({ images }, async () => {
|
||||
// Check that a single image is returned when given entire object
|
||||
expect(
|
||||
db.models('image').select().where(IMAGE_TO_REMOVE),
|
||||
).to.eventually.have.lengthOf(1);
|
||||
// Check that only one image with this dockerImageId exists in the db
|
||||
expect(
|
||||
db
|
||||
.models('image')
|
||||
.where({ dockerImageId: IMAGE_TO_REMOVE.dockerImageId })
|
||||
.select(),
|
||||
).to.eventually.have.lengthOf(1);
|
||||
// Now remove this image...
|
||||
await Images.remove(IMAGE_TO_REMOVE);
|
||||
// Check that docker does not have this image
|
||||
await expect(docker.getImage(IMAGE_TO_REMOVE.name).inspect()).to
|
||||
.eventually.be.empty;
|
||||
// Check that the database longer has this image
|
||||
await expect(db.models('image').select().where(IMAGE_TO_REMOVE)).to
|
||||
.eventually.be.empty;
|
||||
// Check that docker remove was called once
|
||||
const removeSteps = _(mockedDockerode.actions)
|
||||
.pickBy({ name: 'remove' })
|
||||
.map()
|
||||
.value();
|
||||
expect(removeSteps).to.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('Removes an Image with digests', async () => {
|
||||
const images = sampleImageData['image-with-digests'].dockerode;
|
||||
const IMAGE_TO_REMOVE = sampleImageData['image-with-digests'].remove;
|
||||
const IMAGES_FROM_DB = sampleImageData['image-with-digests'].database;
|
||||
// Stub the database to return images we want
|
||||
mockedDatabase.setImages(IMAGES_FROM_DB).stub();
|
||||
// Perform the test with our specially crafted data
|
||||
await mockedDockerode.testWithData({ images }, async () => {
|
||||
// Check that a single image is returned when given entire object
|
||||
expect(
|
||||
db.models('image').select().where(IMAGE_TO_REMOVE),
|
||||
).to.eventually.have.lengthOf(1);
|
||||
// Check that multiple images with the same dockerImageId are returned
|
||||
expect(
|
||||
db
|
||||
.models('image')
|
||||
.where({ dockerImageId: IMAGE_TO_REMOVE.dockerImageId })
|
||||
.select(),
|
||||
).to.eventually.have.lengthOf(2);
|
||||
// Now remove these image...
|
||||
await Images.remove(IMAGE_TO_REMOVE);
|
||||
// Check that docker does not have this image
|
||||
await expect(docker.getImage(IMAGE_TO_REMOVE.name).inspect()).to
|
||||
.eventually.be.empty;
|
||||
// Check that the database no longer has this image
|
||||
await expect(db.models('image').select().where(IMAGE_TO_REMOVE)).to
|
||||
.eventually.be.empty;
|
||||
// Check that docker remove was called twice
|
||||
const removeSteps = _(mockedDockerode.actions)
|
||||
.pickBy({ name: 'remove' })
|
||||
.map()
|
||||
.value();
|
||||
expect(removeSteps).to.have.lengthOf(2);
|
||||
});
|
||||
});
|
||||
});
|
408
test/data/compose-image-data.json
Normal file
408
test/data/compose-image-data.json
Normal file
@ -0,0 +1,408 @@
|
||||
{
|
||||
"legacy-image": {
|
||||
"remove": {
|
||||
"id": 246,
|
||||
"name": "registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650325,
|
||||
"serviceName": "app_1",
|
||||
"imageId": 2693229,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0
|
||||
},
|
||||
"database": [
|
||||
{
|
||||
"id": 246,
|
||||
"name": "registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650325,
|
||||
"serviceName": "app_1",
|
||||
"imageId": 2693229,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0
|
||||
}
|
||||
],
|
||||
"dockerode": {
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492712,
|
||||
"Id": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:72b80cbd3cc12de08d4adc9dec79916bf466031553f55b59c29e397829ea129f"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a:delta-ada9fbb57d90e61e"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024648,
|
||||
"VirtualSize": 217024648
|
||||
},
|
||||
"livepush-supervisor:11.12.11": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492599,
|
||||
"Id": "sha256:db5af2c94366275d8e6d7ea3047f2405eab2f04a27f66843634a45958ef59f5a",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.livepush-image": "1",
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "sha256:4acb1652178e72c0b6143a08225e0df5ef74b338a0c9e2ca4cd261339f4f0431",
|
||||
"RepoDigests": null,
|
||||
"RepoTags": [
|
||||
"livepush-supervisor:11.12.11"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 501352885,
|
||||
"VirtualSize": 501352885
|
||||
}
|
||||
}
|
||||
},
|
||||
"single-image": {
|
||||
"remove": {
|
||||
"id": 246,
|
||||
"name": "registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650325,
|
||||
"serviceName": "app_1",
|
||||
"imageId": 2693229,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0,
|
||||
"dockerImageId": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7"
|
||||
},
|
||||
"database": [
|
||||
{
|
||||
"id": 246,
|
||||
"name": "registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650325,
|
||||
"serviceName": "app_1",
|
||||
"imageId": 2693229,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0,
|
||||
"dockerImageId": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7"
|
||||
},
|
||||
{
|
||||
"id": 247,
|
||||
"name": "registry2.balena-cloud.com/v2/902cf44eb0ed51675a0bf95a7bbf0c91@sha256:12345a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650331,
|
||||
"serviceName": "app_2",
|
||||
"imageId": 2693230,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0,
|
||||
"dockerImageId": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc901234"
|
||||
}
|
||||
],
|
||||
"dockerode": {
|
||||
"sha256:acf4069b3cf68d05dc8a2df0e511447927303ebef88f897f05cbad823f240d97": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492964,
|
||||
"Id": "sha256:acf4069b3cf68d05dc8a2df0e511447927303ebef88f897f05cbad823f240d97",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/772eca412ce780e860b988da6ea26ee0@sha256:7d5e55d6aac00b8504c5c360a3ee59677fc5a7324360f1f54df19d0bb17c2cfe",
|
||||
"registry2.balena-cloud.com/v2/7f1290fa85b253936ebf6e0dbbd95875@sha256:107f63eb1bc2e9978f2a4bb5b095bc010dd91dd5a6a0a39a494e27ee8b396232"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/772eca412ce780e860b988da6ea26ee0:delta-ff3f0a82c404830b",
|
||||
"registry2.balena-cloud.com/v2/7f1290fa85b253936ebf6e0dbbd95875:delta-79acb6d8bf4795f6"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024666,
|
||||
"VirtualSize": 217024666
|
||||
},
|
||||
"sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492712,
|
||||
"Id": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:72b80cbd3cc12de08d4adc9dec79916bf466031553f55b59c29e397829ea129f"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a:delta-ada9fbb57d90e61e"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024648,
|
||||
"VirtualSize": 217024648
|
||||
},
|
||||
"sha256:db5af2c94366275d8e6d7ea3047f2405eab2f04a27f66843634a45958ef59f5a": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492599,
|
||||
"Id": "sha256:db5af2c94366275d8e6d7ea3047f2405eab2f04a27f66843634a45958ef59f5a",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.livepush-image": "1",
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "sha256:4acb1652178e72c0b6143a08225e0df5ef74b338a0c9e2ca4cd261339f4f0431",
|
||||
"RepoDigests": null,
|
||||
"RepoTags": [
|
||||
"livepush-supervisor:11.12.11"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 501352885,
|
||||
"VirtualSize": 501352885
|
||||
},
|
||||
"sha256:272c54e27104cf6c2153538165dba3c29b58ae35837b47134fa55b53ddb61154": {
|
||||
"Containers": -1,
|
||||
"Created": 1599181227,
|
||||
"Id": "sha256:272c54e27104cf6c2153538165dba3c29b58ae35837b47134fa55b53ddb61154",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/459bffd69101d788cc3e0722a012878a@sha256:3cc9231cf0e117585e53ebfa6bf9f75a9a4eaa371fb82c21ab9bca8fe0d5c3e3",
|
||||
"registry2.balena-cloud.com/v2/b0cfe2b1e8c5ab3b6da23f0bd92045b4@sha256:ba5f6d1849c63c8d0f11f35fce694464240002d2c3732898935bf0fedf451063"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/459bffd69101d788cc3e0722a012878a:delta-80ed841a1d3fefa9",
|
||||
"registry2.balena-cloud.com/v2/b0cfe2b1e8c5ab3b6da23f0bd92045b4:delta-532f970c60decb81"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024558,
|
||||
"VirtualSize": 217024558
|
||||
},
|
||||
"sha256:25d6abae14f08de6b80f9d95003e674598738959a535a2f21be34c03675ebd02": {
|
||||
"Containers": -1,
|
||||
"Created": 1599146808,
|
||||
"Id": "sha256:25d6abae14f08de6b80f9d95003e674598738959a535a2f21be34c03675ebd02",
|
||||
"Labels": {
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"balena/aarch64-supervisor@sha256:e7e3b166e855f4c113a67bc528b4ef77408d05e280052f35452f3e2cd7b5322b"
|
||||
],
|
||||
"RepoTags": [
|
||||
"balena/aarch64-supervisor:v11.14.0"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 72305850,
|
||||
"VirtualSize": 72305850
|
||||
},
|
||||
"sha256:60783b8688d395f9b4ce4b288d941244d1b0a4c43114ba980acd012ccffc6b53": {
|
||||
"Containers": -1,
|
||||
"Created": 1585746557,
|
||||
"Id": "sha256:60783b8688d395f9b4ce4b288d941244d1b0a4c43114ba980acd012ccffc6b53",
|
||||
"Labels": {
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"balenalib/aarch64-alpine-supervisor-base@sha256:6eb712fc797ff68f258d9032cf292c266cb9bd8be4cbdaaafeb5a8824bb104fd"
|
||||
],
|
||||
"RepoTags": [
|
||||
"balenalib/aarch64-alpine-supervisor-base:3.11"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 14503741,
|
||||
"VirtualSize": 14503741
|
||||
},
|
||||
"sha256:a29f45ccde2ac0bde957b1277b1501f471960c8ca49f1588c6c885941640ae60": {
|
||||
"Containers": -1,
|
||||
"Created": 1578015959,
|
||||
"Id": "sha256:a29f45ccde2ac0bde957b1277b1501f471960c8ca49f1588c6c885941640ae60",
|
||||
"Labels": null,
|
||||
"ParentId": "",
|
||||
"RepoDigests": null,
|
||||
"RepoTags": [
|
||||
"balena-healthcheck-image:latest"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 9136,
|
||||
"VirtualSize": 9136
|
||||
}
|
||||
}
|
||||
},
|
||||
"image-with-digests": {
|
||||
"remove": {
|
||||
"id": 246,
|
||||
"name": "registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650325,
|
||||
"serviceName": "app_1",
|
||||
"imageId": 2693229,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0,
|
||||
"dockerImageId": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7"
|
||||
},
|
||||
"database": [
|
||||
{
|
||||
"id": 246,
|
||||
"name": "registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650325,
|
||||
"serviceName": "app_1",
|
||||
"imageId": 2693229,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0,
|
||||
"dockerImageId": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7"
|
||||
},
|
||||
{
|
||||
"id": 247,
|
||||
"name": "registry2.balena-cloud.com/v2/902cf44eb0ed51675a0bf95a7bbf0c91@sha256:2c969a1ba1c6bc10df53481f48c6a74dbd562cfb41ba58f81beabd03facf5582",
|
||||
"appId": 1658654,
|
||||
"serviceId": 650331,
|
||||
"serviceName": "app_2",
|
||||
"imageId": 2693230,
|
||||
"releaseId": 1524186,
|
||||
"dependent": 0,
|
||||
"dockerImageId": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7"
|
||||
}
|
||||
],
|
||||
"dockerode": {
|
||||
"sha256:acf4069b3cf68d05dc8a2df0e511447927303ebef88f897f05cbad823f240d97": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492964,
|
||||
"Id": "sha256:acf4069b3cf68d05dc8a2df0e511447927303ebef88f897f05cbad823f240d97",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/772eca412ce780e860b988da6ea26ee0@sha256:7d5e55d6aac00b8504c5c360a3ee59677fc5a7324360f1f54df19d0bb17c2cfe",
|
||||
"registry2.balena-cloud.com/v2/7f1290fa85b253936ebf6e0dbbd95875@sha256:107f63eb1bc2e9978f2a4bb5b095bc010dd91dd5a6a0a39a494e27ee8b396232"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/772eca412ce780e860b988da6ea26ee0:delta-ff3f0a82c404830b",
|
||||
"registry2.balena-cloud.com/v2/7f1290fa85b253936ebf6e0dbbd95875:delta-79acb6d8bf4795f6"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024666,
|
||||
"VirtualSize": 217024666
|
||||
},
|
||||
"sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492712,
|
||||
"Id": "sha256:f1154d76c731f04711e5856b6e6858730e3023d9113124900ac65c2ccc90e8e7",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a@sha256:72b80cbd3cc12de08d4adc9dec79916bf466031553f55b59c29e397829ea129f"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/793f9296017bbfe026334820ab56bb3a:delta-ada9fbb57d90e61e"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024648,
|
||||
"VirtualSize": 217024648
|
||||
},
|
||||
"sha256:db5af2c94366275d8e6d7ea3047f2405eab2f04a27f66843634a45958ef59f5a": {
|
||||
"Containers": -1,
|
||||
"Created": 1599492599,
|
||||
"Id": "sha256:db5af2c94366275d8e6d7ea3047f2405eab2f04a27f66843634a45958ef59f5a",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.livepush-image": "1",
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "sha256:4acb1652178e72c0b6143a08225e0df5ef74b338a0c9e2ca4cd261339f4f0431",
|
||||
"RepoDigests": null,
|
||||
"RepoTags": [
|
||||
"livepush-supervisor:11.12.11"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 501352885,
|
||||
"VirtualSize": 501352885
|
||||
},
|
||||
"sha256:272c54e27104cf6c2153538165dba3c29b58ae35837b47134fa55b53ddb61154": {
|
||||
"Containers": -1,
|
||||
"Created": 1599181227,
|
||||
"Id": "sha256:272c54e27104cf6c2153538165dba3c29b58ae35837b47134fa55b53ddb61154",
|
||||
"Labels": {
|
||||
"io.balena.architecture": "aarch64",
|
||||
"io.balena.device-type": "jetson-tx2",
|
||||
"io.balena.qemu.version": "4.0.0+balena2-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"registry2.balena-cloud.com/v2/459bffd69101d788cc3e0722a012878a@sha256:3cc9231cf0e117585e53ebfa6bf9f75a9a4eaa371fb82c21ab9bca8fe0d5c3e3",
|
||||
"registry2.balena-cloud.com/v2/b0cfe2b1e8c5ab3b6da23f0bd92045b4@sha256:ba5f6d1849c63c8d0f11f35fce694464240002d2c3732898935bf0fedf451063"
|
||||
],
|
||||
"RepoTags": [
|
||||
"registry2.balena-cloud.com/v2/459bffd69101d788cc3e0722a012878a:delta-80ed841a1d3fefa9",
|
||||
"registry2.balena-cloud.com/v2/b0cfe2b1e8c5ab3b6da23f0bd92045b4:delta-532f970c60decb81"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 217024558,
|
||||
"VirtualSize": 217024558
|
||||
},
|
||||
"sha256:25d6abae14f08de6b80f9d95003e674598738959a535a2f21be34c03675ebd02": {
|
||||
"Containers": -1,
|
||||
"Created": 1599146808,
|
||||
"Id": "sha256:25d6abae14f08de6b80f9d95003e674598738959a535a2f21be34c03675ebd02",
|
||||
"Labels": {
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"balena/aarch64-supervisor@sha256:e7e3b166e855f4c113a67bc528b4ef77408d05e280052f35452f3e2cd7b5322b"
|
||||
],
|
||||
"RepoTags": [
|
||||
"balena/aarch64-supervisor:v11.14.0"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 72305850,
|
||||
"VirtualSize": 72305850
|
||||
},
|
||||
"sha256:60783b8688d395f9b4ce4b288d941244d1b0a4c43114ba980acd012ccffc6b53": {
|
||||
"Containers": -1,
|
||||
"Created": 1585746557,
|
||||
"Id": "sha256:60783b8688d395f9b4ce4b288d941244d1b0a4c43114ba980acd012ccffc6b53",
|
||||
"Labels": {
|
||||
"io.balena.qemu.version": "4.0.0+balena-aarch64"
|
||||
},
|
||||
"ParentId": "",
|
||||
"RepoDigests": [
|
||||
"balenalib/aarch64-alpine-supervisor-base@sha256:6eb712fc797ff68f258d9032cf292c266cb9bd8be4cbdaaafeb5a8824bb104fd"
|
||||
],
|
||||
"RepoTags": [
|
||||
"balenalib/aarch64-alpine-supervisor-base:3.11"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 14503741,
|
||||
"VirtualSize": 14503741
|
||||
},
|
||||
"sha256:a29f45ccde2ac0bde957b1277b1501f471960c8ca49f1588c6c885941640ae60": {
|
||||
"Containers": -1,
|
||||
"Created": 1578015959,
|
||||
"Id": "sha256:a29f45ccde2ac0bde957b1277b1501f471960c8ca49f1588c6c885941640ae60",
|
||||
"Labels": null,
|
||||
"ParentId": "",
|
||||
"RepoDigests": null,
|
||||
"RepoTags": [
|
||||
"balena-healthcheck-image:latest"
|
||||
],
|
||||
"SharedSize": -1,
|
||||
"Size": 9136,
|
||||
"VirtualSize": 9136
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
68
test/lib/mocked-database.ts
Normal file
68
test/lib/mocked-database.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import * as _ from 'lodash';
|
||||
import { SinonStub, stub } from 'sinon';
|
||||
import { QueryBuilder } from 'knex';
|
||||
|
||||
import * as db from '../../src/db';
|
||||
import { Image } from '../../src/compose/images';
|
||||
|
||||
let modelStub: SinonStub | null = null;
|
||||
// MOCKED MODELS
|
||||
const MOCKED_MODELS: Dictionary<QueryBuilder> = {};
|
||||
// MOCKED MODEL TYPES
|
||||
let MOCKED_IMAGES: Image[] = [];
|
||||
|
||||
export function create(): SinonStub {
|
||||
if (modelStub === null) {
|
||||
modelStub = stub(db, 'models');
|
||||
// Stub model requests to return our stubbed models
|
||||
modelStub.callsFake((model: string) => {
|
||||
return MOCKED_MODELS[model];
|
||||
});
|
||||
}
|
||||
return modelStub;
|
||||
}
|
||||
|
||||
export function restore(): void {
|
||||
if (modelStub !== null) {
|
||||
modelStub.restore();
|
||||
}
|
||||
}
|
||||
|
||||
export function setImages(images: Image[]) {
|
||||
MOCKED_IMAGES = images;
|
||||
return {
|
||||
stub: stubImages,
|
||||
};
|
||||
}
|
||||
|
||||
function stubImages() {
|
||||
// Set the functions for this model (add them as you need for your test cases)
|
||||
MOCKED_MODELS['image'] = ({
|
||||
select: () => {
|
||||
return {
|
||||
where: async (condition: Partial<Image>) =>
|
||||
_(MOCKED_IMAGES).pickBy(condition).map().value(),
|
||||
};
|
||||
},
|
||||
where: (condition: Partial<Image>) => {
|
||||
return {
|
||||
select: async () => _(MOCKED_IMAGES).pickBy(condition).map().value(),
|
||||
};
|
||||
},
|
||||
del: () => {
|
||||
return {
|
||||
where: async (condition: Partial<Image>) => {
|
||||
return _(MOCKED_IMAGES)
|
||||
.pickBy(condition)
|
||||
.map()
|
||||
.value()
|
||||
.forEach((val) => {
|
||||
MOCKED_IMAGES = _.reject(MOCKED_IMAGES, {
|
||||
id: val.id,
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
} as unknown) as QueryBuilder;
|
||||
}
|
28
test/lib/mocked-dbus.ts
Normal file
28
test/lib/mocked-dbus.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import * as dbus from 'dbus';
|
||||
import { DBusError, DBusInterface } from 'dbus';
|
||||
import { stub } from 'sinon';
|
||||
|
||||
stub(dbus, 'getBus').returns({
|
||||
getInterface: (
|
||||
_serviceName: string,
|
||||
_objectPath: string,
|
||||
_interfaceName: string,
|
||||
interfaceCb: (err: null | DBusError, iface: DBusInterface) => void,
|
||||
) => {
|
||||
interfaceCb(null, {
|
||||
Get: (
|
||||
_unitName: string,
|
||||
_property: string,
|
||||
getCb: (err: null | Error, value: unknown) => void,
|
||||
) => {
|
||||
getCb(null, 'this is the value');
|
||||
},
|
||||
GetUnit: (
|
||||
_unitName: string,
|
||||
getUnitCb: (err: null | Error, unitPath: string) => void,
|
||||
) => {
|
||||
getUnitCb(null, 'this is the unit path');
|
||||
},
|
||||
} as any);
|
||||
},
|
||||
} as any);
|
@ -15,6 +15,24 @@ export class NotFoundError extends TypedError {
|
||||
|
||||
const overrides: Dictionary<(...args: any[]) => Resolvable<any>> = {};
|
||||
|
||||
interface Action {
|
||||
name: string;
|
||||
parameters: Dictionary<any>;
|
||||
}
|
||||
|
||||
export let actions: Action[] = [];
|
||||
|
||||
export function resetHistory() {
|
||||
actions = [];
|
||||
}
|
||||
|
||||
function addAction(name: string, parameters: Dictionary<any>) {
|
||||
actions.push({
|
||||
name,
|
||||
parameters,
|
||||
});
|
||||
}
|
||||
|
||||
type DockerodeFunction = keyof dockerode;
|
||||
for (const fn of Object.getOwnPropertyNames(dockerode.prototype)) {
|
||||
if (
|
||||
@ -62,18 +80,28 @@ export interface TestData {
|
||||
function createMockedDockerode(data: TestData) {
|
||||
const mockedDockerode = dockerode.prototype;
|
||||
mockedDockerode.getNetwork = (id: string) => {
|
||||
addAction('getNetwork', { id });
|
||||
return {
|
||||
inspect: async () => {
|
||||
addAction('inspect', {});
|
||||
return data.networks[id];
|
||||
},
|
||||
} as dockerode.Network;
|
||||
};
|
||||
|
||||
mockedDockerode.getImage = (name: string) => {
|
||||
addAction('getImage', { name });
|
||||
return {
|
||||
inspect: async () => {
|
||||
addAction('inspect', {});
|
||||
return data.images[name];
|
||||
},
|
||||
remove: async () => {
|
||||
addAction('remove', {});
|
||||
data.images = _.reject(data.images, {
|
||||
name,
|
||||
});
|
||||
},
|
||||
} as dockerode.Image;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user