Files
immich/server/src/domain/domain.constant.spec.ts
martin 1aae29a0b8 refactor(server, web)!: store latest immich version available on the server (#3565)
* refactor: store latest immich version available on the server

* don't store admins acknowledgement

* merge main

* fix: api

* feat: custom interval

* pr feedback

* remove unused code

* update environment-variables

* pr feedback

* ci: fix server tests

* fix: dart number

* pr feedback

* remove proxy

* pr feedback

* feat: make stringToVersion more flexible

* feat(web): disable check

* feat: working version

* remove env

* fix: check if interval exists when updating the interval

* feat: show last check

* fix: tests

* fix: remove availableVersion when updated

* fix merge

* fix: web

* fix e2e tests

* merge main

* merge main

* pr feedback

* pr feedback

* fix: tests

* pr feedback

* pr feedback

* pr feedback

* pr feedback

* pr feedback

* fix: migration

* regenerate api

* fix: typo

* fix: compare versions

* pr feedback

* fix

* pr feedback

* fix: checkIntervalTime on startup

* refactor: websockets and interval logic

* chore: open api

* chore: remove unused code

* fix: use interval instead of cron

* mobile: handle WS event data as json object

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2023-10-24 11:05:42 -04:00

263 lines
11 KiB
TypeScript

import { ServerVersion, mimeTypes } from './domain.constant';
describe('mimeTypes', () => {
for (const { mimetype, extension } of [
// Please ensure this list is sorted.
{ mimetype: 'image/3fr', extension: '.3fr' },
{ mimetype: 'image/ari', extension: '.ari' },
{ mimetype: 'image/arw', extension: '.arw' },
{ mimetype: 'image/avif', extension: '.avif' },
{ mimetype: 'image/cap', extension: '.cap' },
{ mimetype: 'image/cin', extension: '.cin' },
{ mimetype: 'image/cr2', extension: '.cr2' },
{ mimetype: 'image/cr3', extension: '.cr3' },
{ mimetype: 'image/crw', extension: '.crw' },
{ mimetype: 'image/dcr', extension: '.dcr' },
{ mimetype: 'image/dng', extension: '.dng' },
{ mimetype: 'image/erf', extension: '.erf' },
{ mimetype: 'image/fff', extension: '.fff' },
{ mimetype: 'image/gif', extension: '.gif' },
{ mimetype: 'image/heic', extension: '.heic' },
{ mimetype: 'image/heif', extension: '.heif' },
{ mimetype: 'image/iiq', extension: '.iiq' },
{ mimetype: 'image/jpeg', extension: '.jpe' },
{ mimetype: 'image/jpeg', extension: '.jpeg' },
{ mimetype: 'image/jpeg', extension: '.jpg' },
{ mimetype: 'image/jxl', extension: '.jxl' },
{ mimetype: 'image/k25', extension: '.k25' },
{ mimetype: 'image/kdc', extension: '.kdc' },
{ mimetype: 'image/mrw', extension: '.mrw' },
{ mimetype: 'image/nef', extension: '.nef' },
{ mimetype: 'image/orf', extension: '.orf' },
{ mimetype: 'image/ori', extension: '.ori' },
{ mimetype: 'image/pef', extension: '.pef' },
{ mimetype: 'image/png', extension: '.png' },
{ mimetype: 'image/psd', extension: '.psd' },
{ mimetype: 'image/raf', extension: '.raf' },
{ mimetype: 'image/raw', extension: '.raw' },
{ mimetype: 'image/rwl', extension: '.rwl' },
{ mimetype: 'image/sr2', extension: '.sr2' },
{ mimetype: 'image/srf', extension: '.srf' },
{ mimetype: 'image/srw', extension: '.srw' },
{ mimetype: 'image/tiff', extension: '.tif' },
{ mimetype: 'image/tiff', extension: '.tiff' },
{ mimetype: 'image/webp', extension: '.webp' },
{ mimetype: 'image/vnd.adobe.photoshop', extension: '.psd' },
{ mimetype: 'image/x-adobe-dng', extension: '.dng' },
{ mimetype: 'image/x-arriflex-ari', extension: '.ari' },
{ mimetype: 'image/x-canon-cr2', extension: '.cr2' },
{ mimetype: 'image/x-canon-cr3', extension: '.cr3' },
{ mimetype: 'image/x-canon-crw', extension: '.crw' },
{ mimetype: 'image/x-epson-erf', extension: '.erf' },
{ mimetype: 'image/x-fuji-raf', extension: '.raf' },
{ mimetype: 'image/x-hasselblad-3fr', extension: '.3fr' },
{ mimetype: 'image/x-hasselblad-fff', extension: '.fff' },
{ mimetype: 'image/x-kodak-dcr', extension: '.dcr' },
{ mimetype: 'image/x-kodak-k25', extension: '.k25' },
{ mimetype: 'image/x-kodak-kdc', extension: '.kdc' },
{ mimetype: 'image/x-leica-rwl', extension: '.rwl' },
{ mimetype: 'image/x-minolta-mrw', extension: '.mrw' },
{ mimetype: 'image/x-nikon-nef', extension: '.nef' },
{ mimetype: 'image/x-olympus-orf', extension: '.orf' },
{ mimetype: 'image/x-olympus-ori', extension: '.ori' },
{ mimetype: 'image/x-panasonic-raw', extension: '.raw' },
{ mimetype: 'image/x-pentax-pef', extension: '.pef' },
{ mimetype: 'image/x-phantom-cin', extension: '.cin' },
{ mimetype: 'image/x-phaseone-cap', extension: '.cap' },
{ mimetype: 'image/x-phaseone-iiq', extension: '.iiq' },
{ mimetype: 'image/x-samsung-srw', extension: '.srw' },
{ mimetype: 'image/x-sigma-x3f', extension: '.x3f' },
{ mimetype: 'image/x-sony-arw', extension: '.arw' },
{ mimetype: 'image/x-sony-sr2', extension: '.sr2' },
{ mimetype: 'image/x-sony-srf', extension: '.srf' },
{ mimetype: 'image/x3f', extension: '.x3f' },
{ mimetype: 'video/3gpp', extension: '.3gp' },
{ mimetype: 'video/avi', extension: '.avi' },
{ mimetype: 'video/mp2t', extension: '.m2ts' },
{ mimetype: 'video/mp2t', extension: '.mts' },
{ mimetype: 'video/mp4', extension: '.mp4' },
{ mimetype: 'video/mpeg', extension: '.mpg' },
{ mimetype: 'video/msvideo', extension: '.avi' },
{ mimetype: 'video/quicktime', extension: '.mov' },
{ mimetype: 'video/vnd.avi', extension: '.avi' },
{ mimetype: 'video/webm', extension: '.webm' },
{ mimetype: 'video/x-flv', extension: '.flv' },
{ mimetype: 'video/x-matroska', extension: '.mkv' },
{ mimetype: 'video/x-ms-wmv', extension: '.wmv' },
{ mimetype: 'video/x-msvideo', extension: '.avi' },
]) {
it(`should map ${extension} to ${mimetype}`, () => {
expect({ ...mimeTypes.image, ...mimeTypes.video }[extension]).toContain(mimetype);
});
}
describe('profile', () => {
it('should contain only lowercase mime types', () => {
const keys = Object.keys(mimeTypes.profile);
expect(keys).toEqual(keys.map((mimeType) => mimeType.toLowerCase()));
const values = Object.values(mimeTypes.profile).flat();
expect(values).toEqual(values.map((mimeType) => mimeType.toLowerCase()));
});
it('should be a sorted list', () => {
const keys = Object.keys(mimeTypes.profile);
// TODO: use toSorted in NodeJS 20.
expect(keys).toEqual([...keys].sort());
});
for (const [ext, v] of Object.entries(mimeTypes.profile)) {
it(`should lookup ${ext}`, () => {
expect(mimeTypes.lookup(`test.${ext}`)).toEqual(v[0]);
});
}
});
describe('image', () => {
it('should contain only lowercase mime types', () => {
const keys = Object.keys(mimeTypes.image);
expect(keys).toEqual(keys.map((mimeType) => mimeType.toLowerCase()));
const values = Object.values(mimeTypes.image).flat();
expect(values).toEqual(values.map((mimeType) => mimeType.toLowerCase()));
});
it('should be a sorted list', () => {
const keys = Object.keys(mimeTypes.image);
// TODO: use toSorted in NodeJS 20.
expect(keys).toEqual([...keys].sort());
});
it('should contain only image mime types', () => {
const values = Object.values(mimeTypes.image).flat();
expect(values).toEqual(values.filter((mimeType) => mimeType.startsWith('image/')));
});
for (const [ext, v] of Object.entries(mimeTypes.image)) {
it(`should lookup ${ext}`, () => {
expect(mimeTypes.lookup(`test.${ext}`)).toEqual(v[0]);
});
}
});
describe('video', () => {
it('should contain only lowercase mime types', () => {
const keys = Object.keys(mimeTypes.video);
expect(keys).toEqual(keys.map((mimeType) => mimeType.toLowerCase()));
const values = Object.values(mimeTypes.video).flat();
expect(values).toEqual(values.map((mimeType) => mimeType.toLowerCase()));
});
it('should be a sorted list', () => {
const keys = Object.keys(mimeTypes.video);
// TODO: use toSorted in NodeJS 20.
expect(keys).toEqual([...keys].sort());
});
it('should contain only video mime types', () => {
const values = Object.values(mimeTypes.video).flat();
expect(values).toEqual(values.filter((mimeType) => mimeType.startsWith('video/')));
});
for (const [ext, v] of Object.entries(mimeTypes.video)) {
it(`should lookup ${ext}`, () => {
expect(mimeTypes.lookup(`test.${ext}`)).toEqual(v[0]);
});
}
});
describe('sidecar', () => {
it('should contain only lowercase mime types', () => {
const keys = Object.keys(mimeTypes.sidecar);
expect(keys).toEqual(keys.map((mimeType) => mimeType.toLowerCase()));
const values = Object.values(mimeTypes.sidecar).flat();
expect(values).toEqual(values.map((mimeType) => mimeType.toLowerCase()));
});
it('should be a sorted list', () => {
const keys = Object.keys(mimeTypes.sidecar);
// TODO: use toSorted in NodeJS 20.
expect(keys).toEqual([...keys].sort());
});
it('should contain only xml mime types', () => {
expect(Object.values(mimeTypes.sidecar).flat()).toEqual(['application/xml', 'text/xml']);
});
for (const [ext, v] of Object.entries(mimeTypes.sidecar)) {
it(`should lookup ${ext}`, () => {
expect(mimeTypes.lookup(`it.${ext}`)).toEqual(v[0]);
});
}
});
});
describe('ServerVersion', () => {
describe('isNewerThan', () => {
it('should work on patch versions', () => {
expect(new ServerVersion(0, 0, 1).isNewerThan(new ServerVersion(0, 0, 0))).toBe(true);
expect(new ServerVersion(1, 72, 1).isNewerThan(new ServerVersion(1, 72, 0))).toBe(true);
expect(new ServerVersion(0, 0, 0).isNewerThan(new ServerVersion(0, 0, 1))).toBe(false);
expect(new ServerVersion(1, 72, 0).isNewerThan(new ServerVersion(1, 72, 1))).toBe(false);
});
it('should work on minor versions', () => {
expect(new ServerVersion(0, 1, 0).isNewerThan(new ServerVersion(0, 0, 0))).toBe(true);
expect(new ServerVersion(1, 72, 0).isNewerThan(new ServerVersion(1, 71, 0))).toBe(true);
expect(new ServerVersion(1, 72, 0).isNewerThan(new ServerVersion(1, 71, 9))).toBe(true);
expect(new ServerVersion(0, 0, 0).isNewerThan(new ServerVersion(0, 1, 0))).toBe(false);
expect(new ServerVersion(1, 71, 0).isNewerThan(new ServerVersion(1, 72, 0))).toBe(false);
expect(new ServerVersion(1, 71, 9).isNewerThan(new ServerVersion(1, 72, 0))).toBe(false);
});
it('should work on major versions', () => {
expect(new ServerVersion(1, 0, 0).isNewerThan(new ServerVersion(0, 0, 0))).toBe(true);
expect(new ServerVersion(2, 0, 0).isNewerThan(new ServerVersion(1, 71, 0))).toBe(true);
expect(new ServerVersion(0, 0, 0).isNewerThan(new ServerVersion(1, 0, 0))).toBe(false);
expect(new ServerVersion(1, 71, 0).isNewerThan(new ServerVersion(2, 0, 0))).toBe(false);
});
it('should work on equal', () => {
for (const version of [
new ServerVersion(0, 0, 0),
new ServerVersion(0, 0, 1),
new ServerVersion(0, 1, 1),
new ServerVersion(0, 1, 0),
new ServerVersion(1, 1, 1),
new ServerVersion(1, 0, 0),
new ServerVersion(1, 72, 1),
new ServerVersion(1, 72, 0),
new ServerVersion(1, 73, 9),
]) {
expect(version.isNewerThan(version)).toBe(false);
}
});
});
describe('fromString', () => {
const tests = [
{ scenario: 'leading v', value: 'v1.72.2', expected: new ServerVersion(1, 72, 2) },
{ scenario: 'uppercase v', value: 'V1.72.2', expected: new ServerVersion(1, 72, 2) },
{ scenario: 'missing v', value: '1.72.2', expected: new ServerVersion(1, 72, 2) },
{ scenario: 'large patch', value: '1.72.123', expected: new ServerVersion(1, 72, 123) },
{ scenario: 'large minor', value: '1.123.0', expected: new ServerVersion(1, 123, 0) },
{ scenario: 'large major', value: '123.0.0', expected: new ServerVersion(123, 0, 0) },
{ scenario: 'major bump', value: 'v2.0.0', expected: new ServerVersion(2, 0, 0) },
];
for (const { scenario, value, expected } of tests) {
it(`should correctly parse ${scenario}`, () => {
const actual = ServerVersion.fromString(value);
expect(actual.major).toEqual(expected.major);
expect(actual.minor).toEqual(expected.minor);
expect(actual.patch).toEqual(expected.patch);
});
}
});
});