Skip to content

Commit 836d40a

Browse files
committed
Skip rfc-9421-test while testing examples
1 parent 24eddc0 commit 836d40a

4 files changed

Lines changed: 31 additions & 73 deletions

File tree

deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@cloudflare/workers-types": "npm:@cloudflare/workers-types@^4.20250529.0",
3737
"@david/dax": "jsr:@david/dax@^0.43.2",
3838
"@fxts/core": "npm:@fxts/core@^1.21.1",
39+
"@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.3.0",
3940
"@js-temporal/polyfill": "npm:@js-temporal/polyfill@^0.5.1",
4041
"@logtape/file": "jsr:@logtape/file@^2.0.0",
4142
"@logtape/logtape": "jsr:@logtape/logtape@^2.0.0",

deno.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/rfc-9421-test/deno.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"imports": {
3-
"@hongminhee/localtunnel": "jsr:@hongminhee/localtunnel@^0.3.0",
43
"hono": "jsr:@hono/hono@^4.7.1"
54
},
65
"tasks": {

examples/test-examples/mod.ts

Lines changed: 29 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
*/
2323

2424
import $, { type CommandChild } from "@david/dax";
25+
import { openTunnel, type Tunnel } from "@hongminhee/localtunnel";
2526
import { configure, getConsoleSink, getLogger } from "@logtape/logtape";
2627
import { fromFileUrl, join } from "@std/path";
2728

@@ -283,6 +284,11 @@ const SKIPPED_EXAMPLES: SkippedExample[] = [
283284
reason:
284285
"No actor dispatcher configured; federation lookup cannot be verified",
285286
},
287+
{
288+
name: "rfc-9421-test",
289+
reason:
290+
"Requires live interaction with external fediverse servers (Bonfire, Mastodon)",
291+
},
286292
];
287293

288294
// ─── ANSI Colors ──────────────────────────────────────────────────────────────
@@ -395,70 +401,22 @@ function forceKillChild(child: CommandChild): void {
395401
// ─── Tunnel ───────────────────────────────────────────────────────────────────
396402

397403
/**
398-
* Starts `fedify tunnel -s pinggy.io <port>` and waits up to `timeoutMs`
399-
* for the tunnel URL to appear in its output. The tunnel process is kept
400-
* alive and returned to the caller; it must be killed when no longer needed.
401-
*
402-
* Returns `null` if the URL was not found before the timeout.
404+
* Opens a tunnel via `@hongminhee/localtunnel` (pinggy.io) to expose
405+
* a local port. Returns the {@link Tunnel} object or `null` on failure.
403406
*/
404-
async function startTunnel(
405-
port: number,
406-
timeoutMs: number,
407-
): Promise<{ child: CommandChild; url: string } | null> {
407+
async function startTunnel(port: number): Promise<Tunnel | null> {
408408
const tunnelLogger = getLogger(["fedify", "examples", "tunnel"]);
409-
tunnelLogger.info("Opening localhost.run tunnel on port {port}", { port });
410-
411-
const child = $`deno task cli tunnel -s pinggy.io ${String(port)}`
412-
.cwd(REPO_ROOT)
413-
.stdout("piped")
414-
.stderr("piped")
415-
.noThrow()
416-
.spawn();
417-
418-
// Accumulate text from both streams while logging each chunk at DEBUG.
419-
const textChunks: string[] = [];
420-
const decoder = new TextDecoder();
421-
422-
const readStream = (stream: ReadableStream<Uint8Array>) => {
423-
(async () => {
424-
const reader = stream.getReader();
425-
try {
426-
while (true) {
427-
const { done, value } = await reader.read();
428-
if (done) break;
429-
const text = decoder.decode(value, { stream: true });
430-
textChunks.push(text);
431-
const trimmed = text.trim();
432-
if (trimmed) tunnelLogger.debug("{output}", { output: trimmed });
433-
}
434-
} catch {
435-
// Stream may error when the process is killed.
436-
}
437-
})();
438-
};
439-
440-
readStream(child.stdout());
441-
readStream(child.stderr());
442-
443-
// Poll until we find an https URL in the accumulated output.
444-
// The `message` template tag from @optique/run may wrap the URL in double
445-
// quotes in non-TTY output, so we stop matching at whitespace or quotes.
446-
const deadline = Date.now() + timeoutMs;
447-
while (Date.now() < deadline) {
448-
const match = textChunks.join("").match(/https:\/\/[^\s"']+/);
449-
if (match) {
450-
tunnelLogger.info("Tunnel established at {url}", { url: match[0] });
451-
return { child, url: match[0] };
452-
}
453-
await new Promise((r) => setTimeout(r, 200));
409+
tunnelLogger.info("Opening tunnel on port {port}", { port });
410+
try {
411+
const tunnel = await openTunnel({ port, service: "pinggy.io" });
412+
tunnelLogger.info("Tunnel established at {url}", {
413+
url: tunnel.url.href,
414+
});
415+
return tunnel;
416+
} catch (error) {
417+
tunnelLogger.error("Failed to open tunnel: {error}", { error });
418+
return null;
454419
}
455-
456-
tunnelLogger.error(
457-
"Tunnel did not produce a URL within {timeout} ms",
458-
{ timeout: timeoutMs },
459-
);
460-
forceKillChild(child);
461-
return null;
462420
}
463421

464422
// ─── Test Runners ─────────────────────────────────────────────────────────────
@@ -549,7 +507,7 @@ async function testServerExample(
549507
const collectServerOutput = () =>
550508
stdoutChunks.join("") + stderrChunks.join("");
551509

552-
let tunnelChild: CommandChild | null = null;
510+
let activeTunnel: Tunnel | null = null;
553511

554512
try {
555513
console.log(
@@ -572,18 +530,18 @@ async function testServerExample(
572530
});
573531
console.log(c.dim(` server ready — opening tunnel on port ${port}…`));
574532

575-
const tunnel = await startTunnel(port, 30_000);
533+
const tunnel = await startTunnel(port);
576534
if (tunnel == null) {
577-
const error = "fedify tunnel did not produce a URL within 30s";
535+
const error = "Failed to open tunnel";
578536
serverLogger.error("{error}", { error });
579537
return { name, status: "fail", error, output: collectServerOutput() };
580538
}
581539

582-
tunnelChild = tunnel.child;
583-
const tunnelHostname = new URL(tunnel.url).hostname;
540+
activeTunnel = tunnel;
541+
const tunnelHostname = tunnel.url.hostname;
584542
const handle = `@${actor}@${tunnelHostname}`;
585543

586-
console.log(c.dim(` tunnel URL : ${tunnel.url}`));
544+
console.log(c.dim(` tunnel URL : ${tunnel.url.href}`));
587545
console.log(c.dim(` running : fedify lookup ${handle} -d`));
588546
serverLogger.info("Running fedify lookup {handle}", { handle });
589547

@@ -606,10 +564,10 @@ async function testServerExample(
606564
serverLogger.error("{error}", { error });
607565
return { name, status: "fail", error, output: lookupOutput };
608566
} finally {
609-
// Force-kill tunnel first (it holds a connection to the server).
610-
if (tunnelChild != null) {
611-
serverLogger.debug("Force-killing tunnel process");
612-
forceKillChild(tunnelChild);
567+
// Close tunnel first (it holds a connection to the server).
568+
if (activeTunnel != null) {
569+
serverLogger.debug("Closing tunnel");
570+
await activeTunnel.close();
613571
}
614572
serverLogger.debug("Force-killing server process");
615573
forceKillChild(serverChild);

0 commit comments

Comments
 (0)