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;
		});
	});
});
