This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a commit to branch feat/template-modes-env-config
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git

commit 9b8cb657e8fd44e23c29bc02d4647cf7004bbf2e
Author: Wu Sheng <[email protected]>
AuthorDate: Fri Jun 26 01:58:24 2026 +0800

    test(bff): readonly-mode sync — renders from disk, includes translation 
overlays, no OAP call
---
 apps/bff/src/logic/templates/sync.test.ts | 67 +++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/apps/bff/src/logic/templates/sync.test.ts 
b/apps/bff/src/logic/templates/sync.test.ts
new file mode 100644
index 0000000..b416292
--- /dev/null
+++ b/apps/bff/src/logic/templates/sync.test.ts
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, it, expect, afterEach } from 'vitest';
+import type { UITemplateClient } from '@skywalking-horizon-ui/api-client';
+import { getSyncStatus, setTemplateReadOnly, invalidateSyncCache } from 
'./sync.js';
+import { iterateBundledTemplates } from './aggregator.js';
+import { logger } from '../../logger.js';
+
+// A client that THROWS on any call — proves readonly mode never touches the
+// OAP ui_template store (it short-circuits to the disk bundle before list()).
+const throwingClient = {
+  list: () => Promise.reject(new Error('ui_template store must not be called 
in readonly mode')),
+  create: () => Promise.reject(new Error('no')),
+  update: () => Promise.reject(new Error('no')),
+  disable: () => Promise.reject(new Error('no')),
+} as unknown as UITemplateClient;
+
+const deps = { client: throwingClient, bundled: () => 
iterateBundledTemplates(), logger };
+
+describe('sync — readonly mode renders from the disk bundle', () => {
+  afterEach(() => {
+    setTemplateReadOnly(false);
+    invalidateSyncCache();
+  });
+
+  it('returns mode=readonly + reachable, without calling the ui_template 
client', async () => {
+    setTemplateReadOnly(true);
+    const status = await getSyncStatus(deps);
+    expect(status.mode).toBe('readonly');
+    expect(status.unreachable).toBe(false);
+    expect(status.rows.length).toBeGreaterThan(0);
+    // Every row is presented as effective:'remote' so every render consumer
+    // resolves it exactly as it would a live remote row.
+    expect(status.rows.every((r) => r.effective === 'remote' && r.remote !== 
null)).toBe(true);
+  });
+
+  it('includes per-locale translation overlay rows so non-English locales 
render translated', async () => {
+    setTemplateReadOnly(true);
+    const status = await getSyncStatus(deps);
+    const overlays = status.rows.filter((r) => r.locale !== undefined);
+    expect(overlays.length).toBeGreaterThan(0);
+    expect(overlays.some((r) => r.locale === 'zh-CN')).toBe(true);
+  });
+
+  it('carries the bundled source rows (layer/overview/alert/...) as effective 
content', async () => {
+    setTemplateReadOnly(true);
+    const status = await getSyncStatus(deps);
+    const kinds = new Set(status.rows.filter((r) => r.locale === 
undefined).map((r) => r.kind));
+    expect(kinds.has('layer')).toBe(true);
+    expect(kinds.has('overview')).toBe(true);
+  });
+});

Reply via email to