balena-supervisor/test/unit/compose/volume.spec.ts
Felipe Lalanne 94de4006a0 Split compose types into interface and implementation
This splits `App`, `Network`, `Service` and `Volume` which used to be
defined as classes into an interface and a class implementation that is
not exported. This will allow to work with just the types in some cases
and prevent circular dependencies when importing.

Change-type: patch
2024-05-27 14:36:03 -04:00

318 lines
8.1 KiB
TypeScript

import { expect } from 'chai';
import { Volume } from '~/src/compose/volume';
describe('compose/volume: unit tests', () => {
describe('creating a volume from a compose object', () => {
it('should use proper defaults when no compose configuration is provided', () => {
const volume = Volume.fromComposeObject(
'my_volume',
1234,
'deadbeef',
{},
);
expect(volume.name).to.equal('my_volume');
expect(volume.appId).to.equal(1234);
expect(volume.appUuid).to.equal('deadbeef');
expect(volume.config).to.deep.equal({
driver: 'local',
driverOpts: {},
labels: {
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
},
});
});
it('should correctly parse compose volumes without an explicit driver', () => {
const volume = Volume.fromComposeObject(
'one_volume',
1032480,
'deadbeef',
{
driver_opts: {
opt1: 'test',
},
labels: {
'my-label': 'test-label',
},
},
);
expect(volume).to.have.property('appId').that.equals(1032480);
expect(volume).to.have.property('name').that.equals('one_volume');
expect(volume)
.to.have.property('config')
.that.has.property('labels')
.that.deep.equals({
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
'my-label': 'test-label',
});
expect(volume)
.to.have.property('config')
.that.has.property('driverOpts')
.that.deep.equals({
opt1: 'test',
});
expect(volume)
.to.have.property('config')
.that.has.property('driver')
.that.equals('local');
});
it('should correctly parse compose volumes with an explicit driver', () => {
const volume = Volume.fromComposeObject(
'one_volume',
1032480,
'deadbeef',
{
driver: 'other',
driver_opts: {
opt1: 'test',
},
labels: {
'my-label': 'test-label',
},
},
);
expect(volume).to.have.property('appId').that.equals(1032480);
expect(volume).to.have.property('name').that.equals('one_volume');
expect(volume)
.to.have.property('config')
.that.has.property('labels')
.that.deep.equals({
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
'my-label': 'test-label',
});
expect(volume)
.to.have.property('config')
.that.has.property('driverOpts')
.that.deep.equals({
opt1: 'test',
});
expect(volume)
.to.have.property('config')
.that.has.property('driver')
.that.equals('other');
});
});
describe('creating a volume instance from a docker volume', () => {
it('should correctly parse app id from volume name', () => {
const volume = Volume.fromDockerVolume({
Driver: 'local',
Name: '1234_my_volume',
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Labels: {},
Options: {},
Scope: 'local',
});
expect(volume.name).to.equal('my_volume');
expect(volume.appId).to.equal(1234);
});
it('should fail if volume name is not properly formatted', () => {
expect(() =>
Volume.fromDockerVolume({
Driver: 'local',
Name: 'non_supervised_volume',
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Labels: {},
Options: {},
Scope: 'local',
}),
).to.throw;
});
it('should correctly parse docker volumes', () => {
const volume = Volume.fromDockerVolume({
Driver: 'local',
Labels: {
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
},
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Name: '1032480_one_volume',
Options: {},
Scope: 'local',
});
expect(volume).to.have.property('appId').that.equals(1032480);
expect(volume).to.have.property('name').that.equals('one_volume');
expect(volume).to.have.property('appUuid').that.equals('deadbeef');
expect(volume)
.to.have.property('config')
.that.has.property('labels')
.that.deep.equals({
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
});
expect(volume)
.to.have.property('config')
.that.has.property('driverOpts')
.that.deep.equals({});
expect(volume)
.to.have.property('config')
.that.has.property('driver')
.that.equals('local');
});
});
describe('comparing volume configuration', () => {
it('should ignore name and supervisor labels in the comparison', () => {
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef').isEqualConfig(
Volume.fromComposeObject('bbb', 4567, 'deadbeef', {
driver: 'local',
driver_opts: {},
}),
),
).to.be.true;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef').isEqualConfig(
Volume.fromComposeObject('bbb', 4567, 'deadc0de'),
),
).to.be.true;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef').isEqualConfig(
Volume.fromDockerVolume({
Name: '1234_aaa',
Driver: 'local',
Labels: {
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
},
Options: {},
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Scope: 'local',
}),
),
).to.be.true;
// the app-uuid should be omitted from the comparison
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef').isEqualConfig(
Volume.fromDockerVolume({
Name: '1234_aaa',
Driver: 'local',
Labels: {
'io.balena.supervised': 'true',
},
Options: {},
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Scope: 'local',
}),
),
).to.be.true;
expect(
Volume.fromComposeObject('aaa', 1234, null as any).isEqualConfig(
Volume.fromDockerVolume({
Name: '4567_bbb',
Driver: 'local',
Labels: {
'io.balena.supervised': 'true',
},
Options: {},
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Scope: 'local',
}),
),
).to.be.true;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef').isEqualConfig(
Volume.fromDockerVolume({
Name: '1234_aaa',
Driver: 'local',
Labels: {
'some.other.label': '123',
'io.balena.supervised': 'true',
'io.balena.app-uuid': 'deadbeef',
},
Options: {},
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Scope: 'local',
}),
),
).to.be.false;
});
it('should compare based on driver configuration and options', () => {
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef').isEqualConfig(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {
driver: 'other',
driver_opts: {},
}),
),
).to.be.false;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {
driver: 'other',
}).isEqualConfig(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {
driver: 'other',
driver_opts: {},
}),
),
).to.be.true;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {}).isEqualConfig(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {
driver_opts: { opt: '123' },
}),
),
).to.be.false;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {
driver: 'other',
labels: { 'some.other.label': '123' },
driver_opts: { 'some-opt': '123' },
}).isEqualConfig(
Volume.fromDockerVolume({
Name: '1234_aaa',
Driver: 'other',
Labels: {
'some.other.label': '123',
'io.balena.supervised': 'true',
},
Options: {},
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Scope: 'local',
}),
),
).to.be.false;
expect(
Volume.fromComposeObject('aaa', 1234, 'deadbeef', {
driver: 'other',
labels: { 'some.other.label': '123' },
driver_opts: { 'some-opt': '123' },
}).isEqualConfig(
Volume.fromDockerVolume({
Name: '1234_aaa',
Driver: 'other',
Labels: {
'some.other.label': '123',
'io.balena.supervised': 'true',
},
Options: { 'some-opt': '123' },
Mountpoint: '/var/lib/docker/volumes/1032480_one_volume/_data',
Scope: 'local',
}),
),
).to.be.true;
});
});
});