test: cover code lease portal paths
This commit is contained in:
parent
b386b9a737
commit
28418c16d0
@ -85,6 +85,25 @@ func TestCloudInitBrowserProfile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudInitCodeProfile(t *testing.T) {
|
||||
cfg := baseConfig()
|
||||
cfg.Code = true
|
||||
got := cloudInit(cfg, "ssh-ed25519 test")
|
||||
for _, want := range []string{
|
||||
"https://code-server.dev/install.sh",
|
||||
"--method=standalone --prefix=/usr/local",
|
||||
"/usr/local/bin/code-server --version >/dev/null",
|
||||
"test -x /usr/local/bin/code-server",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("cloudInit(code) missing %q", want)
|
||||
}
|
||||
}
|
||||
if strings.Contains(cloudInit(baseConfig(), "ssh-ed25519 test"), "code-server") {
|
||||
t.Fatal("cloudInit should not install code-server by default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudInitTailscaleProfile(t *testing.T) {
|
||||
cfg := baseConfig()
|
||||
cfg.SSHUser = "runner"
|
||||
|
||||
46
internal/cli/code_test.go
Normal file
46
internal/cli/code_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWebCodeURLs(t *testing.T) {
|
||||
if got := webCodeAgentURL("https://crabbox.openclaw.ai", "cbx_abcdef123456", "code_abc"); got != "wss://crabbox.openclaw.ai/v1/leases/cbx_abcdef123456/code/agent?ticket=code_abc" {
|
||||
t.Fatalf("agent URL=%q", got)
|
||||
}
|
||||
if got := webCodePortalURL("https://crabbox.openclaw.ai/", "cbx_abcdef123456"); got != "https://crabbox.openclaw.ai/portal/leases/cbx_abcdef123456/code/" {
|
||||
t.Fatalf("portal URL=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodeUpstreamPathStripsPortalLeasePrefix(t *testing.T) {
|
||||
tests := map[string]string{
|
||||
"/portal/leases/cbx_abcdef123456/code/": "/",
|
||||
"/portal/leases/cbx_abcdef123456/code/static/main.js": "/static/main.js",
|
||||
"/portal/leases/cbx_abcdef123456/code/?folder=/work/repo": "/?folder=/work/repo",
|
||||
"/portal/leases/blue-lobster/code/vscode-remote-resource": "/vscode-remote-resource",
|
||||
"/portal/leases/blue-lobster/vnc/viewer": "/portal/leases/blue-lobster/vnc/viewer",
|
||||
"/portal/leases/blue-lobster/code/proxy/3000/?q=hello+you": "/proxy/3000/?q=hello+you",
|
||||
}
|
||||
for input, want := range tests {
|
||||
if got := codeUpstreamPath(input); got != want {
|
||||
t.Fatalf("codeUpstreamPath(%q)=%q want %q", input, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartCodeServerCommand(t *testing.T) {
|
||||
got := startCodeServerCommand("/work/crabbox/cbx_abcdef123456/repo")
|
||||
for _, want := range []string{
|
||||
"/usr/local/bin/code-server",
|
||||
"--auth none",
|
||||
"--bind-addr 127.0.0.1:8080",
|
||||
"VSCODE_PROXY_URI='./proxy/{{port}}'",
|
||||
"/tmp/crabbox-code-server.log",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("startCodeServerCommand missing %q:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1668,7 +1668,7 @@ function codeLeaseError(lease: LeaseRecord): string {
|
||||
if (!lease.code) {
|
||||
return "lease was not created with code=true";
|
||||
}
|
||||
if (lease.target !== "linux") {
|
||||
if (lease.target && lease.target !== "linux") {
|
||||
return "code is currently available for Linux leases only";
|
||||
}
|
||||
if (!lease.host) {
|
||||
|
||||
@ -104,6 +104,16 @@ describe("cloud-init bootstrap", () => {
|
||||
expect(got).toContain('"$BROWSER" --version >/dev/null');
|
||||
});
|
||||
|
||||
it("adds code-server setup only when requested", () => {
|
||||
const plain = cloudInit(config);
|
||||
expect(plain).not.toContain("code-server");
|
||||
const got = cloudInit({ ...config, code: true });
|
||||
expect(got).toContain("https://code-server.dev/install.sh");
|
||||
expect(got).toContain("--method=standalone --prefix=/usr/local");
|
||||
expect(got).toContain("/usr/local/bin/code-server --version >/dev/null");
|
||||
expect(got).toContain("test -x /usr/local/bin/code-server");
|
||||
});
|
||||
|
||||
it("adds Tailscale setup only when requested", () => {
|
||||
const plain = cloudInit(config);
|
||||
expect(plain).not.toContain("tailscale up");
|
||||
|
||||
@ -473,6 +473,7 @@ describe("fleet lease identity and idle", () => {
|
||||
owner: "peter@example.com",
|
||||
org: "openclaw",
|
||||
desktop: true,
|
||||
code: true,
|
||||
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
||||
}),
|
||||
);
|
||||
@ -499,9 +500,71 @@ describe("fleet lease identity and idle", () => {
|
||||
const body = await response.text();
|
||||
expect(body).toContain("blue-lobster");
|
||||
expect(body).toContain("/portal/leases/cbx_000000000001/vnc");
|
||||
expect(body).toContain("/portal/leases/cbx_000000000001/code/");
|
||||
expect(body).not.toContain("amber-krill");
|
||||
});
|
||||
|
||||
it("serves code pages only for code leases and requires a bridge ticket", async () => {
|
||||
const storage = new MemoryStorage();
|
||||
const fleet = testFleet(storage);
|
||||
const headers = {
|
||||
"x-crabbox-owner": "peter@example.com",
|
||||
"x-crabbox-org": "openclaw",
|
||||
};
|
||||
storage.seed(
|
||||
"lease:cbx_000000000001",
|
||||
testLease({
|
||||
id: "cbx_000000000001",
|
||||
slug: "blue-lobster",
|
||||
owner: "peter@example.com",
|
||||
org: "openclaw",
|
||||
code: true,
|
||||
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
||||
}),
|
||||
);
|
||||
storage.seed(
|
||||
"lease:cbx_000000000002",
|
||||
testLease({
|
||||
id: "cbx_000000000002",
|
||||
slug: "plain-lobster",
|
||||
owner: "peter@example.com",
|
||||
org: "openclaw",
|
||||
code: false,
|
||||
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
||||
}),
|
||||
);
|
||||
|
||||
const page = await fleet.fetch(request("GET", "/portal/leases/blue-lobster/code/", { headers }));
|
||||
expect(page.status).toBe(200);
|
||||
const pageBody = await page.text();
|
||||
expect(pageBody).toContain("crabbox code --id blue-lobster --open");
|
||||
|
||||
const plain = await fleet.fetch(
|
||||
request("GET", "/portal/leases/plain-lobster/code/", { headers }),
|
||||
);
|
||||
expect(plain.status).toBe(409);
|
||||
|
||||
const ticket = await fleet.fetch(
|
||||
request("POST", "/v1/leases/blue-lobster/code/ticket", { headers, body: {} }),
|
||||
);
|
||||
expect(ticket.status).toBe(200);
|
||||
const ticketBody = (await ticket.json()) as { ticket: string; leaseID: string };
|
||||
expect(ticketBody.ticket).toMatch(/^code_[a-f0-9]{32}$/);
|
||||
expect(ticketBody.leaseID).toBe("cbx_000000000001");
|
||||
|
||||
const agent = await fleet.fetch(
|
||||
request("GET", "/v1/leases/blue-lobster/code/agent", { headers }),
|
||||
);
|
||||
expect(agent.status).toBe(426);
|
||||
|
||||
const missingTicket = await fleet.fetch(
|
||||
request("GET", "/v1/leases/blue-lobster/code/agent", {
|
||||
headers: { upgrade: "websocket" },
|
||||
}),
|
||||
);
|
||||
expect(missingTicket.status).toBe(401);
|
||||
});
|
||||
|
||||
it("serves WebVNC pages only for desktop leases and requires an agent upgrade", async () => {
|
||||
const storage = new MemoryStorage();
|
||||
const fleet = testFleet(storage);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user