ALL

For reading and verification only. You may not copy, use, modify or redistribute this code. Full notice on the main page.

tunnel/nodeproc_test.go

SHA-256: bd578137294317aae70136121a8462799817f56d873117d0cc06a4694aa26e61
74 lines · 2385 bytes · View on GitHub

1package main
2
3import (
4 "bufio"
5 "bytes"
6 "crypto/ed25519"
7 "crypto/rand"
8 "crypto/x509"
9 "encoding/json"
10 "os"
11 "os/exec"
12 "path/filepath"
13 "testing"
14 "time"
15)
16
17// nodeProc is the test-node binary running as a process, with a device the fake control plane knows.
18type nodeProc struct {
19 e *testEnv
20 d *testDevice
21 cmd *exec.Cmd
22 exited chan error
23 logs *syncBuf
24 control string
25 feed string
26 ready map[string]any // the node's ready line
27}
28
29// launchTestNode starts the test node with one paid device (valid for validFor seconds) and the extra flags, and waits for its ready line.
30func launchTestNode(t *testing.T, validFor int, extra ...string) *nodeProc {
31 t.Helper()
32 bin := testNodeBinary(t)
33 dir := t.TempDir()
34 pub, priv, _ := ed25519.GenerateKey(rand.Reader)
35 jwks, control, certOut := filepath.Join(dir, "jwks.json"), filepath.Join(dir, "control.json"), filepath.Join(dir, "node.pem")
36 jwksFile(t, jwks, testKID, pub)
37 e := &testEnv{t: t, cpKey: priv, tapByID: map[string]*bytes.Buffer{}}
38 e.srv = &Server{nodeURL: nodeProofURL(testNodeHost, 443)}
39 d := e.newDeviceNoPlan()
40 writeControl(t, control, map[string]any{d.id: map[string]any{"host": d.host, "status": "active", "plan": "paid", "valid_for_s": validFor}})
41 args := append([]string{"-https-addr", "127.0.0.1:0", "-http-addr", "127.0.0.1:0", "-node-id", testNodeID, "-node-host", testNodeHost,
42 "-test-jwks", jwks, "-test-control", control, "-test-cert-out", certOut, "-log-level", "info"}, extra...)
43 cmd := exec.Command(bin, args...)
44 stdout, _ := cmd.StdoutPipe()
45 p := &nodeProc{e: e, d: d, cmd: cmd, exited: make(chan error, 1), logs: &syncBuf{}, control: control}
46 cmd.Stderr = p.logs
47 if err := cmd.Start(); err != nil {
48 t.Fatal(err)
49 }
50 go func() { p.exited <- cmd.Wait() }()
51 t.Cleanup(func() { _ = cmd.Process.Kill() })
52 ready := make(chan map[string]any, 1)
53 go func() {
54 line, _ := bufio.NewReader(stdout).ReadString('\n')
55 var m map[string]any
56 if json.Unmarshal([]byte(line), &m) == nil {
57 ready <- m
58 }
59 }()
60 select {
61 case info := <-ready:
62 e.httpsAddr = info["https"].(string)
63 p.ready = info
64 case <-time.After(20 * time.Second):
65 t.Fatalf("the test node did not announce itself:\n%s", p.logs.String())
66 }
67 certPEM, err := os.ReadFile(certOut)
68 if err != nil {
69 t.Fatal(err)
70 }
71 e.nodePool = x509.NewCertPool()
72 e.nodePool.AppendCertsFromPEM(certPEM)
73 return p
74}