mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-25 21:29:01 +03:00
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
130 lines
4.6 KiB
TypeScript
130 lines
4.6 KiB
TypeScript
/**
|
|
* Semantic Search settings tests -- MEDIUM tier.
|
|
*
|
|
* Focuses on the model_size field, which is unused when a GenAI embeddings
|
|
* provider is selected as the semantic search model. The resolved config always
|
|
* reports model_size (it has a schema default of "small"), even when the YAML
|
|
* file has no such key. Clearing model_size for a provider used to run
|
|
* unconditionally, which falsely marked the section dirty on load and asked the
|
|
* backend to delete a key that wasn't in the config file (KeyError: 'model_size').
|
|
*/
|
|
|
|
import { readFileSync } from "node:fs";
|
|
import { resolve, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { test, expect } from "../../fixtures/frigate-test";
|
|
import type { Page } from "@playwright/test";
|
|
import { configFactory } from "../../fixtures/mock-data/config";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const CONFIG_SCHEMA = JSON.parse(
|
|
readFileSync(
|
|
resolve(__dirname, "../../fixtures/mock-data/config-schema.json"),
|
|
"utf-8",
|
|
),
|
|
);
|
|
|
|
const PROVIDER = "llama_cpp";
|
|
const SETTINGS_URL = "/settings?page=integrationSemanticSearch";
|
|
const NOT_APPLICABLE = "Not applicable for GenAI providers";
|
|
const UNSAVED = "You have unsaved changes";
|
|
|
|
type SemanticSearch = {
|
|
enabled?: boolean;
|
|
model?: string;
|
|
model_size?: string;
|
|
};
|
|
|
|
async function installRoutes(page: Page, semanticSearch: SemanticSearch) {
|
|
const config = configFactory({
|
|
genai: { [PROVIDER]: { provider: PROVIDER, roles: ["embeddings"] } },
|
|
semantic_search: semanticSearch,
|
|
});
|
|
|
|
let lastSavedConfig: unknown = null;
|
|
|
|
await page.route("**/api/config/schema.json", (route) =>
|
|
route.fulfill({ json: CONFIG_SCHEMA }),
|
|
);
|
|
await page.route("**/api/config", (route) => {
|
|
if (route.request().method() === "GET") {
|
|
return route.fulfill({ json: config });
|
|
}
|
|
return route.fulfill({ json: { success: true } });
|
|
});
|
|
await page.route("**/api/config/set", async (route) => {
|
|
lastSavedConfig = route.request().postDataJSON();
|
|
await route.fulfill({ json: { success: true, require_restart: false } });
|
|
});
|
|
await page.route("**/api/config/raw_paths", (route) =>
|
|
route.fulfill({ json: { semantic_search: semanticSearch } }),
|
|
);
|
|
|
|
return { capturedConfig: () => lastSavedConfig };
|
|
}
|
|
|
|
test.describe("semantic search model_size @medium", () => {
|
|
test("a provider with a defaulted model_size is not dirty on load", async ({
|
|
frigateApp,
|
|
}) => {
|
|
// model_size stays at its schema default ("small"), i.e. it is not present
|
|
// in the YAML. This mirrors the reported bug: selecting a GenAI provider and
|
|
// returning to the page.
|
|
await installRoutes(frigateApp.page, {
|
|
enabled: true,
|
|
model: PROVIDER,
|
|
});
|
|
await frigateApp.goto(SETTINGS_URL);
|
|
|
|
// The provider path is active: model_size shows "Not applicable".
|
|
await expect(frigateApp.page.getByText(NOT_APPLICABLE)).toBeVisible();
|
|
|
|
// Give any clearing effect time to fire, then confirm the section stayed
|
|
// clean (no phantom unsaved-changes banner, Save disabled).
|
|
await frigateApp.page.waitForTimeout(1000);
|
|
await expect(frigateApp.page.getByText(UNSAVED)).toBeHidden();
|
|
await expect(
|
|
frigateApp.page.getByRole("button", { name: "Save", exact: true }),
|
|
).toBeDisabled();
|
|
});
|
|
|
|
test("switching from a configured non-default model_size clears it", async ({
|
|
frigateApp,
|
|
}) => {
|
|
// A genuinely configured non-default model_size ("large") can only come from
|
|
// the YAML, so switching to a provider must still remove it.
|
|
const capture = await installRoutes(frigateApp.page, {
|
|
enabled: true,
|
|
model: "jinav2",
|
|
model_size: "large",
|
|
});
|
|
await frigateApp.goto(SETTINGS_URL);
|
|
|
|
// Starts clean on a Jina model.
|
|
await expect(frigateApp.page.getByText(UNSAVED)).toBeHidden();
|
|
|
|
// Switch the model to the GenAI provider.
|
|
await frigateApp.page
|
|
.getByRole("combobox", { name: /Semantic search model/ })
|
|
.click();
|
|
await frigateApp.page.getByRole("option", { name: PROVIDER }).click();
|
|
|
|
// The change is now dirty and model_size is no longer applicable.
|
|
await expect(frigateApp.page.getByText(NOT_APPLICABLE)).toBeVisible();
|
|
await expect(frigateApp.page.getByText(UNSAVED)).toBeVisible();
|
|
|
|
await frigateApp.page
|
|
.getByRole("button", { name: "Save", exact: true })
|
|
.click();
|
|
|
|
// The saved payload removes model_size (empty string = "remove" key).
|
|
await expect
|
|
.poll(() => capture.capturedConfig(), { timeout: 5_000 })
|
|
.toMatchObject({
|
|
config_data: {
|
|
semantic_search: { model: PROVIDER, model_size: "" },
|
|
},
|
|
});
|
|
});
|
|
});
|