refactor: rename internal Fai* design system + fai_ helpers to chain
Some checks failed
Security / Security check (push) Failing after 2s
Some checks failed
Security / Security check (push) Failing after 2s
The Studio design system, widgets and helpers carried a Fai* / fai_ prefix (FaiSpace, FaiColors, FaiTheme, FaiLog, 17 fai_*.dart files, the faiBinary* l10n keys). Studio is the Ch∆In product, so rename them to Chain* / chain_ — carefully preserving English fail/failure/failed. Also fix stale references: the 'fai' binary in l10n strings -> 'chain', FAI_* env vars (FAI_BIN/DATA_DIR/MODULES_DIR/TODAY/BOOTSTRAP_TOKEN) -> CHAIN_*, fai_platform -> fai_chain, fai_hub -> chain_hub. Vendor security-hook tooling (FAI_BANNED_TERMS_FILE) + the .fai bundle ext left. flutter analyze + test: clean (20 passed). Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
68d23ab7dd
commit
891acd2ba2
52 changed files with 1225 additions and 1225 deletions
|
|
@ -1,36 +1,36 @@
|
|||
// Unit tests for FaiLog — the central error log that
|
||||
// Unit tests for ChainLog — the central error log that
|
||||
// `~/.fai/logs/studio-errors.log` is the operator-visible
|
||||
// surface of. The tests redirect the singleton at a temp file
|
||||
// via `FaiLog.testPathOverride` so the real log under HOME is
|
||||
// via `ChainLog.testPathOverride` so the real log under HOME is
|
||||
// never touched.
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:chain_studio/data/fai_log.dart';
|
||||
import 'package:chain_studio/data/chain_log.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('FaiLog', () {
|
||||
group('ChainLog', () {
|
||||
late Directory tmp;
|
||||
late File logFile;
|
||||
|
||||
setUp(() {
|
||||
tmp = Directory.systemTemp.createTempSync('fai_log_test_');
|
||||
tmp = Directory.systemTemp.createTempSync('chain_log_test_');
|
||||
logFile = File('${tmp.path}/studio-errors.log');
|
||||
FaiLog.testPathOverride = logFile.path;
|
||||
ChainLog.testPathOverride = logFile.path;
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
FaiLog.testPathOverride = null;
|
||||
ChainLog.testPathOverride = null;
|
||||
try {
|
||||
tmp.deleteSync(recursive: true);
|
||||
} catch (_) {/* best-effort */}
|
||||
});
|
||||
|
||||
test('append writes one JSON-shaped line per event', () async {
|
||||
await FaiLog.instance.error('flows.run', 'boom');
|
||||
final lines = await FaiLog.instance.tail();
|
||||
await ChainLog.instance.error('flows.run', 'boom');
|
||||
final lines = await ChainLog.instance.tail();
|
||||
expect(lines, hasLength(1));
|
||||
final entry = jsonDecode(lines.single) as Map<String, Object?>;
|
||||
expect(entry['source'], 'flows.run');
|
||||
|
|
@ -40,22 +40,22 @@ void main() {
|
|||
});
|
||||
|
||||
test('context field is preserved when supplied', () async {
|
||||
await FaiLog.instance.error(
|
||||
await ChainLog.instance.error(
|
||||
'theme.plugin.load',
|
||||
Exception('endpoint unreachable'),
|
||||
context: 'capability=studio.theme.space',
|
||||
);
|
||||
final lines = await FaiLog.instance.tail();
|
||||
final lines = await ChainLog.instance.tail();
|
||||
final entry = jsonDecode(lines.single) as Map<String, Object?>;
|
||||
expect(entry['context'], 'capability=studio.theme.space');
|
||||
expect(entry['error'], contains('endpoint unreachable'));
|
||||
});
|
||||
|
||||
test('tail returns oldest first', () async {
|
||||
await FaiLog.instance.error('a', '1');
|
||||
await FaiLog.instance.error('b', '2');
|
||||
await FaiLog.instance.error('c', '3');
|
||||
final lines = await FaiLog.instance.tail();
|
||||
await ChainLog.instance.error('a', '1');
|
||||
await ChainLog.instance.error('b', '2');
|
||||
await ChainLog.instance.error('c', '3');
|
||||
final lines = await ChainLog.instance.tail();
|
||||
expect(lines, hasLength(3));
|
||||
final sources = lines.map((l) => jsonDecode(l)['source']).toList();
|
||||
expect(sources, ['a', 'b', 'c']);
|
||||
|
|
@ -63,9 +63,9 @@ void main() {
|
|||
|
||||
test('tail caps output at maxLines and keeps the newest', () async {
|
||||
for (var i = 0; i < 20; i++) {
|
||||
await FaiLog.instance.error('burst', 'event-$i');
|
||||
await ChainLog.instance.error('burst', 'event-$i');
|
||||
}
|
||||
final lines = await FaiLog.instance.tail(maxLines: 5);
|
||||
final lines = await ChainLog.instance.tail(maxLines: 5);
|
||||
expect(lines, hasLength(5));
|
||||
final last = jsonDecode(lines.last) as Map<String, Object?>;
|
||||
expect(last['error'], 'event-19');
|
||||
|
|
@ -77,7 +77,7 @@ void main() {
|
|||
// `.log.1` and a short fresh `.log`.
|
||||
logFile.parent.createSync(recursive: true);
|
||||
logFile.writeAsBytesSync(List.filled(257 * 1024, 0x20));
|
||||
await FaiLog.instance.error('rotation', 'after-cap');
|
||||
await ChainLog.instance.error('rotation', 'after-cap');
|
||||
expect(File('${logFile.path}.1').existsSync(), isTrue);
|
||||
final newSize = logFile.lengthSync();
|
||||
expect(newSize, lessThan(2 * 1024));
|
||||
|
|
@ -86,16 +86,16 @@ void main() {
|
|||
});
|
||||
|
||||
test('path getter returns the override when set', () {
|
||||
expect(FaiLog.instance.path, logFile.path);
|
||||
expect(ChainLog.instance.path, logFile.path);
|
||||
});
|
||||
|
||||
test('writes failing silently does not throw', () async {
|
||||
// Redirect to a deliberately impossible path. The error()
|
||||
// call must complete cleanly; the operator UI must never
|
||||
// crash because the disk is full / read-only / missing.
|
||||
FaiLog.testPathOverride = '/this/path/does/not/exist/ever/x.log';
|
||||
ChainLog.testPathOverride = '/this/path/does/not/exist/ever/x.log';
|
||||
await expectLater(
|
||||
FaiLog.instance.error('bad.path', 'boom'),
|
||||
ChainLog.instance.error('bad.path', 'boom'),
|
||||
completes,
|
||||
);
|
||||
});
|
||||
|
|
@ -35,14 +35,14 @@ flutter test test/integration/
|
|||
```
|
||||
|
||||
Prereq: a `fai` binary on PATH or at
|
||||
`../fai_platform/target/release/fai`. The harness skips with a
|
||||
`../fai_chain/target/release/chain`. The harness skips with a
|
||||
clear message when neither exists, so this command does not
|
||||
fail on a fresh checkout — it just reports skipped tests.
|
||||
|
||||
To get the binary:
|
||||
|
||||
```bash
|
||||
cd ../fai_platform
|
||||
cd ../fai_chain
|
||||
cargo build --release --bin fai
|
||||
```
|
||||
|
||||
|
|
@ -52,11 +52,11 @@ A cold `chain serve` spends its first ~30s building the
|
|||
curated-model database and initialising SQLite migrations.
|
||||
`HubFixture.start()` waits up to 60s by default; if your local
|
||||
hub takes longer the first time, run `chain serve` once by hand
|
||||
against any temp `FAI_DATA_DIR` to warm the per-user cargo /
|
||||
against any temp `CHAIN_DATA_DIR` to warm the per-user cargo /
|
||||
SBOM caches:
|
||||
|
||||
```bash
|
||||
FAI_DATA_DIR=/tmp/fai_warmup chain serve --bind 127.0.0.1:0
|
||||
CHAIN_DATA_DIR=/tmp/chain_warmup chain serve --bind 127.0.0.1:0
|
||||
# wait for "hub started", Ctrl-C
|
||||
```
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ Subsequent integration-test runs are quick.
|
|||
|
||||
`.forgejo/workflows/ci.yml` doesn't run these yet. Adding them
|
||||
needs an artifact-passing pattern: the platform build job
|
||||
publishes `target/release/fai` as a CI artifact; the studio
|
||||
publishes `target/release/chain` as a CI artifact; the studio
|
||||
test job consumes it. Pattern is straightforward once we want
|
||||
it; it's deferred because we don't yet have enough integration
|
||||
tests to justify the CI runtime.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
// flutter test test/integration/
|
||||
//
|
||||
// CI does not yet run these by default — they need a built `fai`
|
||||
// binary in PATH or in ../fai_platform/target/release/. Wire that
|
||||
// binary in PATH or in ../chain_platform/target/release/. Wire that
|
||||
// in via .forgejo/workflows/ci.yml once the platform CI publishes
|
||||
// a Linux binary as an artifact for downstream jobs to consume.
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class HubFixture {
|
|||
if (skipIfBinaryMissing) {
|
||||
markTestSkipped(
|
||||
'Hub fixture skipped: no `fai` binary found on PATH or in '
|
||||
'../fai_platform/target/release/fai. Build it with '
|
||||
'../chain_platform/target/release/fai. Build it with '
|
||||
'`cargo build --release` and re-run.',
|
||||
);
|
||||
return null;
|
||||
|
|
@ -86,15 +86,15 @@ class HubFixture {
|
|||
|
||||
// Run as a child process. `serve --bind` lets us avoid the
|
||||
// default 50051 (and any local daemon the developer happens
|
||||
// to be running). FAI_DATA_DIR keeps the temp footprint
|
||||
// to be running). CHAIN_DATA_DIR keeps the temp footprint
|
||||
// contained — no state leaks into ~/.fai.
|
||||
final process = await Process.start(
|
||||
binary,
|
||||
['serve', '--bind', addr],
|
||||
environment: {
|
||||
...Platform.environment,
|
||||
'FAI_DATA_DIR': tempDir.path,
|
||||
'FAI_MODULES_DIR': '${tempDir.path}/modules',
|
||||
'CHAIN_DATA_DIR': tempDir.path,
|
||||
'CHAIN_MODULES_DIR': '${tempDir.path}/modules',
|
||||
// Suppress info logs without a CLI flag — the binary
|
||||
// respects RUST_LOG for tracing-subscriber.
|
||||
'RUST_LOG': 'warn',
|
||||
|
|
@ -136,7 +136,7 @@ class HubFixture {
|
|||
await tempDir.delete(recursive: true);
|
||||
throw StateError(
|
||||
'Hub did not become healthy within $readyTimeout. '
|
||||
'Check `fai serve` works manually with FAI_DATA_DIR=$tempDir.',
|
||||
'Check `fai serve` works manually with CHAIN_DATA_DIR=$tempDir.',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +172,8 @@ class HubFixture {
|
|||
}
|
||||
|
||||
final candidate = Platform.isWindows
|
||||
? '../fai_platform/target/release/fai.exe'
|
||||
: '../fai_platform/target/release/fai';
|
||||
? '../chain_platform/target/release/fai.exe'
|
||||
: '../chain_platform/target/release/fai';
|
||||
final f = File(candidate);
|
||||
if (await f.exists()) {
|
||||
return f.absolute.path;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
// flutter test test/integration/plugin_theme_test.dart
|
||||
//
|
||||
// Pre-reqs (handled by HubFixture's skip-when-missing path):
|
||||
// - fai binary on PATH or at ../fai_platform/target/release/fai
|
||||
// - fai binary on PATH or at ../chain_platform/target/release/fai
|
||||
// - studio-theme-solarized plugin built to module.wasm in its
|
||||
// fai_plugins dir.
|
||||
// chain_plugins dir.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ void main() {
|
|||
// add network + bundle-fetch latency that doesn't
|
||||
// belong in an in-process round-trip test.
|
||||
final pluginSrc = Directory(
|
||||
'../fai_plugins/studio-theme-solarized',
|
||||
'../chain_plugins/studio-theme-solarized',
|
||||
);
|
||||
if (!await pluginSrc.exists()) {
|
||||
markTestSkipped('studio-theme-solarized source not available');
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import 'package:chain_studio/l10n/app_localizations.dart';
|
|||
import 'package:chain_studio/theme/theme.dart';
|
||||
|
||||
/// Recreates the exact DocReaderSheet code path that
|
||||
/// welcome.dart uses, including FaiTheme.markdownStyle, so a
|
||||
/// welcome.dart uses, including ChainTheme.markdownStyle, so a
|
||||
/// regression in either rootBundle, the markdown parser, or
|
||||
/// the style sheet surfaces here instead of only at runtime
|
||||
/// when an operator clicks a doc card.
|
||||
|
|
@ -16,7 +16,7 @@ void main() {
|
|||
|
||||
testWidgets('DocReaderSheet renders all four german + english docs',
|
||||
(tester) async {
|
||||
final theme = FaiTheme.light();
|
||||
final theme = ChainTheme.light();
|
||||
for (final slug in ['architecture', 'security', 'audit', 'flows']) {
|
||||
for (final locale in ['de', 'en']) {
|
||||
final path = locale == 'de'
|
||||
|
|
@ -39,7 +39,7 @@ void main() {
|
|||
data: text,
|
||||
padding: const EdgeInsets.all(8),
|
||||
selectable: true,
|
||||
styleSheet: FaiTheme.markdownStyle(theme),
|
||||
styleSheet: ChainTheme.markdownStyle(theme),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue