Files
openobserve/web/src/composables/useTracePatternTree.spec.ts
T
Hengfei Yang 8303be0b4c refactor: rename AlertManager node role to Scheduler (#13696)
## Summary

- rename the `AlertManager` node role to `Scheduler` across Rust
services, jobs, protobuf bindings, UI labels, and tests
- emit `scheduler` as the canonical role name
- continue accepting legacy `alertmanager` and `alert_manager`
configuration values
- keep protobuf enum value `5` unchanged for wire compatibility

## Why

The role schedules and executes alerts, reports, pipelines, synthetics,
and other background work. `Scheduler` describes that broader
responsibility more accurately.

## Compatibility

- existing role configuration values remain accepted through parser and
serde aliases
- the protobuf numeric value remains stable
- coordinated changes are included in the Enterprise, Helm chart, and
documentation repositories

## Verification

- `cargo test -p config test_role`
- `cargo test -p openobserve-node`
- `cargo check -p openobserve-jobs`
- targeted web tests: 307 passed, 13 skipped
- Rust formatting and targeted Prettier checks
2026-08-07 13:30:38 +00:00

95 lines
4.0 KiB
TypeScript

// Copyright 2026 OpenObserve Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { describe, expect, it } from "vitest";
import { ref } from "vue";
import { useTracePatternTree } from "@/composables/useTracePatternTree";
import { buildPatternConsolidatedTree } from "@/utils/traces/patternDetection";
import { patternTraceTrees } from "@/test/unit/mockData/traces";
// Runs the same pipeline TraceDetails uses for the Trace Graph tab:
// traceTree → buildPatternConsolidatedTree → useTracePatternTree.treeData
const getTreeData = (traceTree: any[]) => {
const patterns = ref(buildPatternConsolidatedTree(traceTree));
const { treeData } = useTracePatternTree(patterns, ref(false));
return treeData.value;
};
describe("useTracePatternTree", () => {
describe("treeData transformation", () => {
it("should build a single root tree when the trace has one root span calling another service", () => {
const treeData = getTreeData(patternTraceTrees.singleRoot);
expect(treeData.length).toBe(1);
expect(treeData[0].name).toBe("scheduler");
expect(treeData[0].children?.map((c) => c.name)).toEqual(["querier"]);
});
it("should build one tree per root service when root spans have distinct services", () => {
const treeData = getTreeData(patternTraceTrees.multiRootDistinctServices);
expect(treeData.map((n) => n.name).sort()).toEqual(["ingester", "scheduler"]);
expect(treeData.find((n) => n.name === "scheduler")?.children?.map((c) => c.name)).toEqual([
"querier",
]);
expect(treeData.find((n) => n.name === "ingester")?.children?.map((c) => c.name)).toEqual([
"compactor",
]);
});
it("should render a service node when all root spans belong to the same service", () => {
const treeData = getTreeData(patternTraceTrees.multiRootSameService);
expect(treeData.length).toBe(1);
expect(treeData[0].name).toBe("scheduler");
// Metrics come from the service's self-pattern (2 spans, avg 75ms)
expect(treeData[0].metadata?.count).toBe(2);
expect(treeData[0].metadata?.avg).toBe(75);
});
it("should render a service node when the trace has a single span and single service", () => {
const treeData = getTreeData(patternTraceTrees.singleServiceOnly);
expect(treeData.length).toBe(1);
expect(treeData[0].name).toBe("scheduler");
expect(treeData[0].metadata?.count).toBe(1);
});
it("should build a tree when root services call each other cyclically", () => {
const treeData = getTreeData(patternTraceTrees.multiRootCyclicServices);
// Cycle scheduler→querier / querier→scheduler: no parentless
// service exists, but both services must still be represented.
expect(treeData.length).toBe(1);
expect(treeData[0].name).toBe("scheduler");
expect(treeData[0].children?.map((c) => c.name)).toEqual(["querier"]);
});
it("should not promote a service to root when it already appears as a child of another root", () => {
const treeData = getTreeData(patternTraceTrees.multiRootOrphanChildService);
expect(treeData.length).toBe(1);
expect(treeData[0].name).toBe("scheduler");
expect(treeData[0].children?.map((c) => c.name)).toEqual(["querier"]);
});
it("should return an empty tree when the pattern map is empty", () => {
const { treeData } = useTracePatternTree(ref(new Map()), ref(false));
expect(treeData.value).toEqual([]);
});
});
});