tstest/integration/vms: make first end to end test (#2332)

This makes sure `tailscale status` and `tailscale ping` works. It also
switches goexpect to use a batch instead of manually banging out each
line, which makes the tests so much easier to read.

Signed-off-by: Christine Dodrill <xe@tailscale.com>
pull/2344/head
Christine Dodrill 3 years ago committed by GitHub
parent 805d5d3cde
commit a8360050e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -627,6 +627,8 @@ func TestVMIntegrationEndToEnd(t *testing.T) {
ramsem := semaphore.NewWeighted(int64(*vmRamLimit)) ramsem := semaphore.NewWeighted(int64(*vmRamLimit))
bins := integration.BuildTestBinaries(t) bins := integration.BuildTestBinaries(t)
makeTestNode(t, bins, loginServer)
t.Run("do", func(t *testing.T) { t.Run("do", func(t *testing.T) {
for n, distro := range distros { for n, distro := range distros {
n, distro := n, distro n, distro := n, distro
@ -718,9 +720,9 @@ func testDistro(t *testing.T, loginServer string, d Distro, signer ssh.Signer, i
expect.Verbose(true), expect.Verbose(true),
expect.VerboseWriter(logger.FuncWriter(t.Logf)), expect.VerboseWriter(logger.FuncWriter(t.Logf)),
// // NOTE(Xe): if you get a timeout, uncomment this line to have the raw // // NOTE(Xe): if you get a timeout, uncomment this region to have the raw
// output be sent to the test log quicker. // // output be sent to the test log quicker.
//expect.Tee(nopWriteCloser{logger.FuncWriter(t.Logf)}), // expect.Tee(nopWriteCloser{logger.FuncWriter(t.Logf)}),
) )
if err != nil { if err != nil {
t.Fatalf("%d: can't register a shell session: %v", port, err) t.Fatalf("%d: can't register a shell session: %v", port, err)
@ -729,11 +731,11 @@ func testDistro(t *testing.T, loginServer string, d Distro, signer ssh.Signer, i
t.Log("opened session") t.Log("opened session")
_, _, err = e.Expect(regexp.MustCompile(`(\#)`), timeout) var batch = []expect.Batcher{
if err != nil { &expect.BSnd{S: "PS1='# '\n"},
t.Fatalf("%d: can't get a shell: %v", port, err) &expect.BExp{R: `(\#)`},
} }
t.Logf("got shell for %d", port)
switch d.initSystem { switch d.initSystem {
case "openrc": case "openrc":
// NOTE(Xe): this is a sin, however openrc doesn't really have the concept // NOTE(Xe): this is a sin, however openrc doesn't really have the concept
@ -741,23 +743,36 @@ func testDistro(t *testing.T, loginServer string, d Distro, signer ssh.Signer, i
// ready once the `tailscale up` command is sent. This is not ideal, but I // ready once the `tailscale up` command is sent. This is not ideal, but I
// am not really sure there is a good way around this without a delay of // am not really sure there is a good way around this without a delay of
// some kind. // some kind.
err = e.Send("rc-service tailscaled start && sleep 2\n") batch = append(batch, &expect.BSnd{S: "rc-service tailscaled start && sleep 2\n"})
case "systemd": case "systemd":
err = e.Send("systemctl start tailscaled.service\n") batch = append(batch, &expect.BSnd{S: "systemctl start tailscaled.service\n"})
} }
if err != nil {
t.Fatalf("can't send command to start tailscaled: %v", err) batch = append(batch,
} &expect.BExp{R: `(\#)`},
_, _, err = e.Expect(regexp.MustCompile(`(\#)`), timeout) &expect.BSnd{S: fmt.Sprintf("tailscale up --login-server=%s\n", loginServer)},
if err != nil { &expect.BExp{R: `Success.`},
t.Fatalf("%d: can't get a shell: %v", port, err) &expect.BSnd{S: "sleep 5 && tailscale status\n"},
} &expect.BExp{R: `100.64.0.1`},
err = e.Send(fmt.Sprintf("tailscale up --login-server %s\n", loginServer)) &expect.BExp{R: `(\#)`},
if err != nil { &expect.BSnd{S: "tailscale ping -c 1 100.64.0.1\n"},
t.Fatalf("%d: can't send tailscale up command: %v", port, err) &expect.BExp{R: `pong from.*\(100.64.0.1\)`},
} &expect.BSnd{S: "ping -c 1 100.64.0.1\n"},
_, _, err = e.Expect(regexp.MustCompile(`Success.`), timeout) &expect.BExp{R: `bytes`},
)
_, err = e.ExpectBatch(batch, timeout)
if err != nil { if err != nil {
sess, terr := cli.NewSession()
if terr != nil {
t.Fatalf("can't dump tailscaled logs on failed test: %v", err)
}
sess.Stdout = logger.FuncWriter(t.Logf)
sess.Stderr = logger.FuncWriter(t.Logf)
terr = sess.Run("journalctl -u tailscaled")
if terr != nil {
t.Fatalf("can't dump tailscaled logs on failed test: %v", err)
}
t.Fatalf("not successful: %v", err) t.Fatalf("not successful: %v", err)
} }
} }
@ -874,6 +889,56 @@ func TestDeriveBindhost(t *testing.T) {
t.Log(deriveBindhost(t)) t.Log(deriveBindhost(t))
} }
func makeTestNode(t *testing.T, bins *integration.Binaries, controlURL string) {
dir := t.TempDir()
cmd := exec.Command(
bins.Daemon,
"--tun=userspace-networking",
"--state="+filepath.Join(dir, "state.json"),
"--socket="+filepath.Join(dir, "sock"),
"--socks5-server=localhost:0",
)
cmd.Env = append(os.Environ(), "NOTIFY_SOCKET="+filepath.Join(dir, "notify_socket"))
err := cmd.Start()
if err != nil {
t.Fatalf("can't start tailscaled: %v", err)
}
t.Cleanup(func() {
cmd.Process.Kill()
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ticker := time.NewTicker(100 * time.Millisecond)
outer:
for {
select {
case <-ctx.Done():
t.Fatal("timed out waiting for tailscaled to come up")
return
case <-ticker.C:
conn, err := net.Dial("unix", filepath.Join(dir, "sock"))
if err != nil {
continue
}
conn.Close()
break outer
}
}
run(t, dir, bins.CLI,
"--socket="+filepath.Join(dir, "sock"),
"up",
"--login-server="+controlURL,
"--hostname=tester",
)
}
type nopWriteCloser struct { type nopWriteCloser struct {
io.Writer io.Writer
} }

Loading…
Cancel
Save