mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-26 05:29:45 +00:00
Keep native maintenance checks compiling and command facts clean
Completed PR2825 CI reports Windows Unix-type compilation failures and three Prettier fixture failures. Compile the existing Linux-only MSP daemon fixture only on Linux and format the unchanged frontend assertions. Separate successful CLI stdout from retained stderr diagnostics so Compose warnings cannot corrupt container identities, ports or bootstrap facts; add three executable controls without changing deadlines or acceptance gates. Change-source: pulse-maintainer
This commit is contained in:
@@ -7781,3 +7781,20 @@ or failed parsers, failed transport with a plausible body, redirects, pins and
|
||||
downgrade refusal. Existing extracted-function tests include the shared selector.
|
||||
These are source-level selection controls, not native installation, published
|
||||
release acceptance or a repair to a third-party community helper.
|
||||
|
||||
|
||||
### Combined-batch native fixture reconciliation (11 October 2026)
|
||||
|
||||
The real provider-MSP startup fixture is Linux-only at compile time, matching
|
||||
its existing Linux transport admission. Its cloud-control-plane import must not
|
||||
pull Unix filesystem types into Windows installer test compilation. Windows
|
||||
installer and lifecycle tests remain enabled; the startup fixture still runs in
|
||||
the Linux process proof and hosted Compose job.
|
||||
|
||||
Successful command stdout alone supplies container identities, published ports
|
||||
and bootstrap facts. Stderr warnings remain logged evidence, never arguments to
|
||||
the next Docker command. Failure diagnostics retain both streams and the original
|
||||
nonzero exit. `TestProviderMSPStartupCommandSeparatesDiagnostics` checks three
|
||||
consumer shapes with controlled successful stderr; it is not Docker acceptance.
|
||||
Hosted mounted-secret/readiness/persistence/refusal/cleanup checks remain required.
|
||||
Frontend fixture reformatting retains all assertions and changes no runtime UI.
|
||||
|
||||
@@ -25,7 +25,9 @@ describe('agent token-file help in the shipped Markdown renderer', () => {
|
||||
expect(link?.getAttribute('href')).toBe(`#${id}`);
|
||||
expect(link?.hasAttribute('data-doc-link')).toBe(false);
|
||||
expect(link?.hasAttribute('target')).toBe(false);
|
||||
expect(article.querySelector(`#${id}`)?.textContent).toBe('Token-file format is not shell syntax');
|
||||
expect(article.querySelector(`#${id}`)?.textContent).toBe(
|
||||
'Token-file format is not shell syntax',
|
||||
);
|
||||
expect(guide).toBe(
|
||||
readFileSync(path.join(repoRoot, 'frontend-modern/public/docs/UNIFIED_AGENT.md'), 'utf8'),
|
||||
);
|
||||
@@ -55,10 +57,15 @@ describe('agent token-file help in the shipped Markdown renderer', () => {
|
||||
].entries()) {
|
||||
expect(rows[index].textContent).toContain(phrase);
|
||||
}
|
||||
const text = parts.map((element) => element.textContent).join(' ').replace(/\s+/g, ' ');
|
||||
const text = parts
|
||||
.map((element) => element.textContent)
|
||||
.join(' ')
|
||||
.replace(/\s+/g, ' ');
|
||||
expect(text).toContain('not the value, length, hint, screenshot or file');
|
||||
expect(text).toContain('Do not print, source, upload or edit the installed token file');
|
||||
expect(text).toContain('not proof of accepted reporting');
|
||||
expect(parts.some((element) => element.matches('pre') || element.querySelector('pre'))).toBe(false);
|
||||
expect(parts.some((element) => element.matches('pre') || element.querySelector('pre'))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,8 @@ import { describe, expect, it } from 'vitest';
|
||||
import { renderDocMarkdown } from '../docMarkdown';
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../..');
|
||||
const guide = (name: string): string => readFileSync(path.join(root, 'frontend-modern/public/docs', `${name}.md`), 'utf8');
|
||||
const guide = (name: string): string =>
|
||||
readFileSync(path.join(root, 'frontend-modern/public/docs', `${name}.md`), 'utf8');
|
||||
const article = (name: string): HTMLElement => {
|
||||
const element = document.createElement('article');
|
||||
element.innerHTML = renderDocMarkdown(guide(name), name);
|
||||
@@ -15,7 +16,11 @@ const section = (): HTMLElement => {
|
||||
const heading = article('FAQ').querySelector('#can-i-disable-alerts-for-specific-metrics');
|
||||
expect(heading).not.toBeNull();
|
||||
const element = document.createElement('section');
|
||||
for (let next = heading!.nextElementSibling; next && !/^H[1-6]$/.test(next.tagName); next = next.nextElementSibling) {
|
||||
for (
|
||||
let next = heading!.nextElementSibling;
|
||||
next && !/^H[1-6]$/.test(next.tagName);
|
||||
next = next.nextElementSibling
|
||||
) {
|
||||
element.appendChild(next.cloneNode(true));
|
||||
}
|
||||
return element;
|
||||
@@ -28,11 +33,14 @@ describe('shipped alert Off FAQ', () => {
|
||||
expect(text).toContain('not every default has a per-resource control');
|
||||
expect(text).toContain('save, then reopen the editor');
|
||||
expect(element.querySelectorAll('li')).toHaveLength(4);
|
||||
for (const phrase of ['does not hide its readings, stop collection',
|
||||
'explicit threshold can remain active', 'Already queued notifications',
|
||||
for (const phrase of [
|
||||
'does not hide its readings, stop collection',
|
||||
'explicit threshold can remain active',
|
||||
'Already queued notifications',
|
||||
'Patrol findings are separate from threshold alerts',
|
||||
'when the corresponding alert default is Off',
|
||||
'Do not induce an alert, send another Test or retry the queue']) {
|
||||
'Do not induce an alert, send another Test or retry the queue',
|
||||
]) {
|
||||
expect(text).toContain(phrase);
|
||||
}
|
||||
expect(element.querySelector('pre')).toBeNull();
|
||||
@@ -42,7 +50,10 @@ describe('shipped alert Off FAQ', () => {
|
||||
it('routes the two independent warning paths to real shipped headings', () => {
|
||||
const links = [...section().querySelectorAll('a')];
|
||||
expect(links).toHaveLength(2);
|
||||
expect(links.map((link) => link.textContent)).toEqual(['how Patrol works', 'ordinary notification checks']);
|
||||
expect(links.map((link) => link.textContent)).toEqual([
|
||||
'how Patrol works',
|
||||
'ordinary notification checks',
|
||||
]);
|
||||
for (const link of links) {
|
||||
const [name, fragment] = link.getAttribute('href')!.replace('/docs/', '').split('#');
|
||||
expect(article(name).querySelector(`#${fragment}`)).not.toBeNull();
|
||||
|
||||
@@ -657,9 +657,7 @@ describe('docsLinks', () => {
|
||||
/if !reportCallerMayUseAI\(ctx\) \{\s*return nil, nil, h\.resolveExistingFindings\(ctx\)\s*\}\s*return h\.narratorResolver\(ctx\)/,
|
||||
);
|
||||
expect(resolver.match(/h\.narratorResolver\(/g)).toHaveLength(1);
|
||||
expect(fleet).toMatch(
|
||||
/_, fleetNarrator, findings := h\.resolveNarrator\(ctx\)/,
|
||||
);
|
||||
expect(fleet).toMatch(/_, fleetNarrator, findings := h\.resolveNarrator\(ctx\)/);
|
||||
expect(fleet.match(/h\.resolveNarrator\(/g)).toHaveLength(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build linux
|
||||
|
||||
package installtests
|
||||
|
||||
import (
|
||||
@@ -265,12 +267,17 @@ func startupCommand(t *testing.T, env []string, dir, program string, args ...str
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, program, args...)
|
||||
cmd.Dir, cmd.Env = dir, env
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout, cmd.Stderr = &stdout, &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
// Environment and licence contents are never diagnostic output.
|
||||
t.Fatalf("%s command failed: %v\n%s", filepath.Base(program), err, output)
|
||||
t.Fatalf("%s command failed: %v\n%s\n%s", filepath.Base(program), err, stdout.String(), stderr.String())
|
||||
}
|
||||
return string(output)
|
||||
if stderr.Len() != 0 {
|
||||
// Compose warnings are evidence, not container IDs, ports or CLI facts.
|
||||
t.Logf("%s diagnostics: %s", filepath.Base(program), stderr.String())
|
||||
}
|
||||
return stdout.String()
|
||||
}
|
||||
|
||||
func startupRefusal(t *testing.T, env []string, dir, want, program string, args ...string) {
|
||||
@@ -384,3 +391,17 @@ func startupFacts(output string) map[string]string {
|
||||
}
|
||||
return facts
|
||||
}
|
||||
|
||||
// Compose may warn on stderr about optional unset variables even when it
|
||||
// succeeds. Never pass those diagnostics as the next docker exec identity.
|
||||
func TestProviderMSPStartupCommandSeparatesDiagnostics(t *testing.T) {
|
||||
for _, value := range []string{"synthetic-container-id", "127.0.0.1:8443", "provider_msp_bootstrap_ok=true"} {
|
||||
t.Run(value, func(t *testing.T) {
|
||||
output := startupCommand(t, []string{"PATH=" + os.Getenv("PATH")}, t.TempDir(), "sh", "-c",
|
||||
`printf '%s\n' "$1"; printf 'optional variable warning\n' >&2`, "fixture", value)
|
||||
if output != value+"\n" {
|
||||
t.Fatalf("command facts include diagnostics: %q", output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user