mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-04 15:06:37 +08:00
497289b462
- Added risk summary metrics including critical alerts, high CPU/memory nodes, and lagging nodes to the dashboard overview. - Introduced peak node metrics for busiest and riskiest nodes with detailed display. - Updated types for dashboard overview to include risk and peak summaries. - Implemented new components for displaying risk signals and peak cards. - Enhanced unit tests to cover new risk and peak metrics in the dashboard overview. fix(update): improve error messages for server upgrade processes - Translated and clarified error messages related to server upgrades and binary uploads. - Ensured consistent error handling and messaging throughout the upgrade process. test(update): refactor test utilities for server upgrade - Renamed roundTripFunc to serverUpdateRoundTripFunc for clarity in test code. - Updated test cases to utilize the new naming convention. feat(node-detail): add traffic structure distribution and health event timeline - Implemented traffic breakdown visualization for status codes and top domains in node detail page. - Added health event timeline to display active and resolved events for better observability. feat(rank-chart): create reusable rank chart component - Developed a new RankChart component for visualizing ranked data distributions. - Integrated RankChart into node detail page for displaying status code and domain distributions.
174 lines
6.2 KiB
TypeScript
174 lines
6.2 KiB
TypeScript
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { render, screen } from '@testing-library/react';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { DashboardOverview } from '@/features/dashboard/components/dashboard-overview';
|
|
|
|
vi.mock('echarts-for-react', () => ({
|
|
default: () => <div data-testid="echarts-mock" />,
|
|
}));
|
|
|
|
describe('DashboardOverview', () => {
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
it('renders dashboard summary cards', async () => {
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn((input: RequestInfo | URL) => {
|
|
const url = String(input);
|
|
|
|
if (url.includes('/dashboard/overview')) {
|
|
return Promise.resolve(
|
|
new Response(
|
|
JSON.stringify({
|
|
success: true,
|
|
message: '',
|
|
data: {
|
|
generated_at: '2026-03-14T08:00:00Z',
|
|
summary: {
|
|
total_nodes: 2,
|
|
online_nodes: 2,
|
|
offline_nodes: 0,
|
|
pending_nodes: 0,
|
|
unhealthy_nodes: 1,
|
|
active_alerts: 1,
|
|
lagging_nodes: 1,
|
|
},
|
|
traffic: {
|
|
request_count: 900,
|
|
unique_visitors: 200,
|
|
error_count: 36,
|
|
estimated_qps: 15,
|
|
reported_nodes: 2,
|
|
},
|
|
capacity: {
|
|
average_cpu_usage_percent: 68.5,
|
|
average_memory_usage_percent: 71.8,
|
|
high_cpu_nodes: 1,
|
|
high_memory_nodes: 1,
|
|
high_storage_nodes: 1,
|
|
},
|
|
config: {
|
|
active_version: '20260314-001',
|
|
lagging_nodes: 1,
|
|
pending_nodes: 0,
|
|
},
|
|
risk: {
|
|
critical_alerts: 1,
|
|
warning_alerts: 2,
|
|
info_alerts: 0,
|
|
offline_nodes: 0,
|
|
unhealthy_nodes: 1,
|
|
lagging_nodes: 1,
|
|
high_cpu_nodes: 1,
|
|
high_memory_nodes: 1,
|
|
high_storage_nodes: 1,
|
|
},
|
|
peaks: {
|
|
peak_request_hour: {
|
|
bucket_started_at: '2026-03-14T08:00:00Z',
|
|
request_count: 900,
|
|
error_count: 36,
|
|
},
|
|
peak_error_hour: {
|
|
bucket_started_at: '2026-03-14T09:00:00Z',
|
|
request_count: 400,
|
|
error_count: 60,
|
|
},
|
|
busiest_node: {
|
|
node_id: 'node-a',
|
|
node_name: 'edge-a',
|
|
request_count: 600,
|
|
error_count: 6,
|
|
cpu_usage_percent: 45,
|
|
active_event_count: 0,
|
|
openresty_status: 'healthy',
|
|
storage_usage_percent: 60,
|
|
},
|
|
riskiest_node: {
|
|
node_id: 'node-b',
|
|
node_name: 'edge-b',
|
|
request_count: 300,
|
|
error_count: 30,
|
|
cpu_usage_percent: 92,
|
|
active_event_count: 2,
|
|
openresty_status: 'unhealthy',
|
|
storage_usage_percent: 95,
|
|
},
|
|
},
|
|
trends: {
|
|
traffic_24h: Array.from({ length: 24 }, (_, index) => ({
|
|
bucket_started_at: `2026-03-13T${String(index).padStart(2, '0')}:00:00Z`,
|
|
request_count: index * 10,
|
|
error_count: index,
|
|
unique_visitor_count: index * 3,
|
|
})),
|
|
capacity_24h: Array.from({ length: 24 }, (_, index) => ({
|
|
bucket_started_at: `2026-03-13T${String(index).padStart(2, '0')}:00:00Z`,
|
|
average_cpu_usage_percent: index,
|
|
average_memory_usage_percent: index + 10,
|
|
reported_nodes: 2,
|
|
})),
|
|
},
|
|
nodes: [
|
|
{
|
|
id: 1,
|
|
node_id: 'node-a',
|
|
name: 'edge-a',
|
|
status: 'online',
|
|
openresty_status: 'healthy',
|
|
current_version: '20260314-001',
|
|
last_seen_at: '2026-03-14T08:00:00Z',
|
|
active_event_count: 0,
|
|
cpu_usage_percent: 45,
|
|
memory_usage_percent: 50,
|
|
storage_usage_percent: 60,
|
|
request_count: 600,
|
|
error_count: 6,
|
|
unique_visitor_count: 120,
|
|
},
|
|
],
|
|
active_alerts: [
|
|
{
|
|
node_id: 'node-b',
|
|
node_name: 'edge-b',
|
|
event_type: 'openresty_unhealthy',
|
|
severity: 'critical',
|
|
message: 'reload failed',
|
|
last_triggered_at: '2026-03-14T07:59:00Z',
|
|
status: 'active',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
return Promise.reject(new Error(`Unhandled fetch: ${url}`));
|
|
}),
|
|
);
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
},
|
|
},
|
|
});
|
|
|
|
render(
|
|
<QueryClientProvider client={queryClient}>
|
|
<DashboardOverview />
|
|
</QueryClientProvider>,
|
|
);
|
|
|
|
expect(await screen.findByText('系统运行总览')).toBeInTheDocument();
|
|
expect(await screen.findByText('风险态势')).toBeInTheDocument();
|
|
expect(await screen.findByText('24 小时请求趋势')).toBeInTheDocument();
|
|
expect(await screen.findByText('节点健康列表')).toBeInTheDocument();
|
|
});
|
|
});
|