diff --git a/src/quality-profiles.test.ts b/src/quality-profiles.test.ts index e3c208b..1855f05 100644 --- a/src/quality-profiles.test.ts +++ b/src/quality-profiles.test.ts @@ -1,9 +1,24 @@ +import path from "path"; import { describe, expect, test } from "vitest"; -import { MergedQualityDefinitionResource } from "./__generated__/mergedTypes"; -import { doAllQualitiesExist, isOrderOfQualitiesEqual, mapQualities } from "./quality-profiles"; -import { ConfigQualityProfile, ConfigQualityProfileItem } from "./types/config.types"; +import { MergedCustomFormatResource, MergedQualityDefinitionResource, MergedQualityProfileResource } from "./__generated__/mergedTypes"; +import { calculateQualityProfilesDiff, doAllQualitiesExist, isOrderOfQualitiesEqual, mapQualities } from "./quality-profiles"; +import { CFProcessing } from "./types/common.types"; +import { ConfigQualityProfile, ConfigQualityProfileItem, MergedConfigInstance } from "./types/config.types"; +import { cloneWithJSON, loadJsonFile } from "./util"; describe("QualityProfiles", async () => { + const sampleQualityProfile = loadJsonFile( + path.resolve(__dirname, `../tests/samples/single_quality_profile.json`), + ); + + const sampleQualityDefinitions = loadJsonFile( + path.resolve(__dirname, `../tests/samples/qualityDefinition.json`), + ); + + const sampleCustomFormat = loadJsonFile( + path.resolve(__dirname, `../tests/samples/single_custom_format.json`), + ); + test("doAllQualitiesExist - all exist", async ({}) => { const fromConfig: ConfigQualityProfileItem[] = [ { name: "WEB 1080p", qualities: ["WEBDL-1080p", "WEBRip-1080p"] }, @@ -184,12 +199,111 @@ describe("QualityProfiles", async () => { expect(result[2]!.allowed).toBe(true); }); - test("calculateQualityProfilesDiff - should diff if minUpgradeFormatScore is different", async ({}) => { - // TODO + test("calculateQualityProfilesDiff - should diff if minUpgradeFormatScore / minFormatScore is different", async ({}) => { + const cfMap: CFProcessing = { carrIdMapping: new Map(), cfNameToCarrConfig: new Map() }; + + const fromConfig: ConfigQualityProfileItem[] = [{ name: "HDTV-1080p", enabled: false }]; + + const resources: MergedQualityDefinitionResource[] = [ + { id: 1, title: "HDTV-1080p", weight: 2, quality: { id: 1, name: "HDTV-1080p" } }, + ]; + + const profile: ConfigQualityProfile = { + name: "hi", + min_format_score: 2, + qualities: fromConfig, + quality_sort: "sort", + upgrade: { allowed: true, until_quality: "HDTV-1080p", until_score: 1000 }, + score_set: "default", + }; + + const config: MergedConfigInstance = { + custom_formats: [], + quality_profiles: [profile], + customFormatDefinitions: [], + media_management: {}, + media_naming: {}, + }; + + const serverProfile = cloneWithJSON(sampleQualityProfile); + serverProfile.name = "hi"; + serverProfile.formatItems = []; + serverProfile.minUpgradeFormatScore = 3; + serverProfile.minFormatScore = 3; + serverProfile.cutoff = 1; + serverProfile.items = [{ allowed: false, items: [], quality: { id: 1, name: "HDTV-1080p" } }]; + + const serverQP: MergedQualityProfileResource[] = [serverProfile]; + const serverQD: MergedQualityDefinitionResource[] = resources; + const serverCF: MergedCustomFormatResource[] = [cloneWithJSON(sampleCustomFormat)]; + + let diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF); + expect(diff.changedQPs.length).toBe(1); + expect(diff.create.length).toBe(0); + expect(diff.noChanges.length).toBe(0); + + serverProfile.minFormatScore = 0; + diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF); + expect(diff.changedQPs.length).toBe(1); + expect(diff.create.length).toBe(0); + expect(diff.noChanges.length).toBe(0); + + serverProfile.minUpgradeFormatScore = 0; + diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF); + expect(diff.changedQPs.length).toBe(1); + expect(diff.create.length).toBe(0); + expect(diff.noChanges.length).toBe(0); + + profile.min_format_score = 0; + serverProfile.minFormatScore = 1; + diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF); + expect(diff.changedQPs.length).toBe(1); + expect(diff.create.length).toBe(0); + expect(diff.noChanges.length).toBe(0); }); - test("calculateQualityProfilesDiff - should not diff if minUpgradeFormatScore is equal", async ({}) => { - // TODO + test("calculateQualityProfilesDiff - should not diff if minFormatScore is equal", async ({}) => { + const cfMap: CFProcessing = { carrIdMapping: new Map(), cfNameToCarrConfig: new Map() }; + + const fromConfig: ConfigQualityProfileItem[] = [{ name: "HDTV-1080p", enabled: false }]; + + const resources: MergedQualityDefinitionResource[] = [ + { id: 1, title: "HDTV-1080p", weight: 2, quality: { id: 1, name: "HDTV-1080p" } }, + ]; + + const profile: ConfigQualityProfile = { + name: "hi", + min_format_score: 2, + qualities: fromConfig, + quality_sort: "sort", + upgrade: { allowed: true, until_quality: "HDTV-1080p", until_score: 1000 }, + score_set: "default", + }; + + const config: MergedConfigInstance = { + custom_formats: [], + quality_profiles: [profile], + customFormatDefinitions: [], + media_management: {}, + media_naming: {}, + }; + + const serverProfile = cloneWithJSON(sampleQualityProfile); + serverProfile.name = "hi"; + serverProfile.formatItems = []; + serverProfile.minUpgradeFormatScore = 3; + serverProfile.minFormatScore = 2; + serverProfile.cutoff = 1; + serverProfile.items = [{ allowed: false, items: [], quality: { id: 1, name: "HDTV-1080p" } }]; + + const serverQP: MergedQualityProfileResource[] = [serverProfile]; + const serverQD: MergedQualityDefinitionResource[] = resources; + const serverCF: MergedCustomFormatResource[] = [cloneWithJSON(sampleCustomFormat)]; + + const diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF); + expect(diff.changedQPs.length).toBe(0); + expect(diff.create.length).toBe(0); + expect(diff.noChanges.length).toBe(1); }); test("calculateQualityProfilesDiff - should not diff if minUpgradeFormatScore is not configured", async ({}) => { diff --git a/src/quality-profiles.ts b/src/quality-profiles.ts index 65ae3a4..52eb73a 100644 --- a/src/quality-profiles.ts +++ b/src/quality-profiles.ts @@ -186,7 +186,7 @@ export const doAllQualitiesExist = (serverResource: ConfigQualityProfileItem[], const sortedServerConfig = serverCloned.sort((a, b) => (a.name < b.name ? -1 : 1)); const sortedLocalConfig = localCloned.sort((a, b) => (a.name < b.name ? -1 : 1)); - if (sortedLocalConfig.length !== sortedServerConfig.length) { + if (sortedLocalConfig.length !== sortedServerConfig.length || sortedLocalConfig.length === 0) { return false; } @@ -256,7 +256,7 @@ export const calculateQualityProfilesDiff = async ( return p; }, new Map()) ?? new Map(); - if (!serverMatch) { + if (serverMatch == null) { logger.info(`QualityProfile '${name}' not found in server. Will be created.`); const mappedQ = mapQualities(serverQD, value); @@ -350,10 +350,10 @@ export const calculateQualityProfilesDiff = async ( // TODO do we want to enforce the whole structure or only match those which are enabled by us? if (!doAllQualitiesExist(serverQualitiesMapped, value.qualities)) { - logger.info(`QualityProfile items mismatch will update whole array`); + logger.info(`QualityProfile qualities mismatch will update whole array`); diffExist = true; - changeList.push(`QualityProfile items do not match`); + changeList.push(`QualityProfile qualities mismatch will update whole array`); updatedServerObject.items = mapQualities(serverQD, value); } else { if (!isOrderOfQualitiesEqual(value.qualities, serverQualitiesMapped.toReversed())) { @@ -378,7 +378,7 @@ export const calculateQualityProfilesDiff = async ( return p; }, new Map()); - if (value.min_format_score) { + if (value.min_format_score != null) { if (serverMatch.minFormatScore !== value.min_format_score) { updatedServerObject.minFormatScore = value.min_format_score; diffExist = true; @@ -386,7 +386,7 @@ export const calculateQualityProfilesDiff = async ( } } - if (value.upgrade) { + if (value.upgrade != null) { if (serverMatch.upgradeAllowed !== value.upgrade.allowed) { updatedServerObject.upgradeAllowed = value.upgrade.allowed; diffExist = true; @@ -396,7 +396,7 @@ export const calculateQualityProfilesDiff = async ( const upgradeUntil = qualityToId.get(value.upgrade.until_quality); - if (!upgradeUntil) { + if (upgradeUntil == null) { throw new Error(`Did not find expected Quality to upgrade until: ${value.upgrade.until_quality}`); } @@ -431,7 +431,7 @@ export const calculateQualityProfilesDiff = async ( let scoringDiff = false; - if (scoringForQP) { + if (scoringForQP != null) { const newCFFormats: MergedProfileFormatItemResource[] = []; for (const [scoreKey, scoreValue] of scoringForQP.entries()) { @@ -477,7 +477,7 @@ export const calculateQualityProfilesDiff = async ( updatedServerObject.formatItems = newCFFormats; } else { - logger.info(`No scoring for QualityProfile ${serverMatch.name!} found`); + logger.info(`No scoring for QualityProfile '${serverMatch.name!}' found`); } logger.debug( diff --git a/tests/samples/single_custom_format.json b/tests/samples/single_custom_format.json new file mode 100644 index 0000000..7a8d294 --- /dev/null +++ b/tests/samples/single_custom_format.json @@ -0,0 +1,28 @@ +{ + "id": 1, + "name": "BR-DISK", + "includeCustomFormatWhenRenaming": false, + "specifications": [ + { + "name": "BR-DISK", + "implementation": "ReleaseTitleSpecification", + "implementationName": "Release Title", + "infoLink": "https://wiki.servarr.com/sonarr/settings#custom-formats-2", + "negate": false, + "required": true, + "fields": [ + { + "order": 0, + "name": "value", + "label": "Regular Expression", + "helpText": "Custom Format RegEx is Case Insensitive", + "value": "^(?!.*\\b((?