Browse Source

control/controlclient: move direct_test back to corp repo.

It can only be built with corp deps anyway, and having it split
from the control code makes our lives harder.

Signed-off-by: David Anderson <[email protected]>
David Anderson 5 years ago
parent
commit
7317e73bf4
1 changed files with 0 additions and 384 deletions
  1. 0 384
      control/controlclient/direct_test.go

+ 0 - 384
control/controlclient/direct_test.go

@@ -1,384 +0,0 @@
-// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build depends_on_currently_unreleased
-
-package controlclient
-
-import (
-	"context"
-	"io/ioutil"
-	"net/http"
-	"net/http/cookiejar"
-	"net/http/httptest"
-	"os"
-	"testing"
-	"time"
-
-	"github.com/klauspost/compress/zstd"
-	"github.com/tailscale/wireguard-go/wgcfg"
-	"tailscale.com/tailcfg"
-	"tailscale.com/tstest"
-	"tailscale.com/types/logger"
-	"tailscale.io/control" // not yet released
-)
-
-// Test that when there are two controlclient connections using the
-// same credentials, the later one disconnects the earlier one.
-func TestDirectReusingKeys(t *testing.T) {
-	tstest.PanicOnLog()
-	rc := tstest.NewResourceCheck()
-	defer rc.Assert(t)
-
-	tmpdir, err := ioutil.TempDir("", "control-test-")
-	if err != nil {
-		t.Fatal(err)
-	}
-	var server *control.Server
-	httpsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		server.ServeHTTP(w, r)
-	}))
-	httpsrv.Config.ErrorLog = logger.StdLogger(t.Logf)
-	defer func() {
-		httpsrv.CloseClientConnections()
-		httpsrv.Close()
-		os.RemoveAll(tmpdir)
-	}()
-
-	httpc := httpsrv.Client()
-	httpc.Jar, err = cookiejar.New(nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	server, err = control.New(tmpdir, tmpdir, tmpdir, httpsrv.URL, true, t.Logf)
-	if err != nil {
-		t.Fatal(err)
-	}
-	server.QuietLogging = true
-	defer server.Shutdown()
-
-	hi := NewHostinfo()
-	hi.FrontendLogID = "go-test-only"
-	hi.BackendLogID = "go-test-only"
-
-	// Let's test some nonempty extra hostinfo fields to make sure
-	// the server can handle them.
-	hi.RequestTags = []string{"tag:abc"}
-	cidr, err := wgcfg.ParseCIDR("1.2.3.4/24")
-	if err != nil {
-		t.Fatalf("ParseCIDR: %v", err)
-	}
-	hi.RoutableIPs = []wgcfg.CIDR{cidr}
-	hi.Services = []tailcfg.Service{
-		{
-			Proto:       tailcfg.TCP,
-			Port:        1234,
-			Description: "Description",
-		},
-	}
-
-	c1, err := NewDirect(Options{
-		ServerURL:      httpsrv.URL,
-		HTTPTestClient: httpsrv.Client(),
-		//TimeNow:   s.control.TimeNow,
-		Logf: func(fmt string, args ...interface{}) {
-			t.Helper()
-			t.Logf("c1: "+fmt, args...)
-		},
-		Hostinfo: hi,
-	})
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Use a cancelable context so that goroutines blocking in
-	// PollNetMap shut down when the test exits.
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-
-	// Execute c1's login flow: TryLogin to get an auth URL,
-	// postAuthURL to execute the (faked) OAuth segment of the flow,
-	// and WaitLoginURL to complete the login on the client end.
-	const user = "[email protected]"
-	authURL, err := c1.TryLogin(ctx, nil, 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	postAuthURL(t, ctx, httpc, user, authURL)
-	newURL, err := c1.WaitLoginURL(ctx, authURL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if newURL != "" {
-		t.Fatalf("unexpected newURL: %s", newURL)
-	}
-
-	// Start c1's netmap poll in parallel with the rest of the
-	// test. We're expecting it to block happily, invoking the no-op
-	// update function periodically, then exit once c2 starts its own
-	// poll below.
-	gotNetmap := make(chan struct{}, 1)
-	pollErrCh := make(chan error, 1)
-	go func() {
-		pollErrCh <- c1.PollNetMap(ctx, -1, func(netMap *NetworkMap) {
-			select {
-			case gotNetmap <- struct{}{}:
-			default:
-			}
-		})
-	}()
-
-	select {
-	case <-gotNetmap:
-		t.Logf("c1: received initial netmap")
-	case err := <-pollErrCh:
-		t.Fatal(err)
-	case <-time.After(5 * time.Second):
-		t.Fatal("c1 did not receive an initial netmap")
-	}
-
-	// Connect c2, reusing c1's credentials. In other words, c2 *is*
-	// c1 from the server's perspective.
-	c2, err := NewDirect(Options{
-		ServerURL:      httpsrv.URL,
-		HTTPTestClient: httpsrv.Client(),
-		Logf: func(fmt string, args ...interface{}) {
-			t.Helper()
-			t.Logf("c2: "+fmt, args...)
-		},
-		Persist:  c1.GetPersist(),
-		Hostinfo: hi,
-		NewDecompressor: func() (Decompressor, error) {
-			return zstd.NewReader(nil,
-				zstd.WithDecoderLowmem(true),
-				zstd.WithDecoderConcurrency(1),
-				zstd.WithDecoderMaxMemory(65536),
-			)
-		},
-		KeepAlive: true,
-	})
-	if err != nil {
-		t.Fatal(err)
-	}
-	authURL, err = c2.TryLogin(ctx, nil, 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// We don't expect to be given an authURL, our credentials from c1
-	// should still be good.
-	if authURL != "" {
-		t.Errorf("unexpected authURL %s", authURL)
-	}
-
-	// Request a single netmap, so this function returns promptly
-	// instead of blocking like c1's PollNetMap.
-	err = c2.PollNetMap(ctx, 1, func(netMap *NetworkMap) {})
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Now that c2 connected and got a netmap, we expect c1's poll to
-	// have exited.
-	select {
-	case err := <-pollErrCh:
-		t.Logf("c1: netmap poll aborted as expected (%v)", err)
-	case <-time.After(5 * time.Second):
-		t.Fatal("first client poll failed to close")
-	}
-}
-
-func TestDirectReusingOldKey(t *testing.T) {
-	tstest.PanicOnLog()
-	rc := tstest.NewResourceCheck()
-	defer rc.Assert(t)
-
-	tmpdir, err := ioutil.TempDir("", "control-test-")
-	if err != nil {
-		t.Fatal(err)
-	}
-	var server *control.Server
-	httpsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		server.ServeHTTP(w, r)
-	}))
-	httpsrv.Config.ErrorLog = logger.StdLogger(t.Logf)
-	defer func() {
-		httpsrv.CloseClientConnections()
-		httpsrv.Close()
-		os.RemoveAll(tmpdir)
-	}()
-
-	httpc := httpsrv.Client()
-	httpc.Jar, err = cookiejar.New(nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	server, err = control.New(tmpdir, tmpdir, tmpdir, httpsrv.URL, true, t.Logf)
-	if err != nil {
-		t.Fatal(err)
-	}
-	server.QuietLogging = true
-	defer server.Shutdown()
-
-	hi := NewHostinfo()
-	hi.FrontendLogID = "go-test-only"
-	hi.BackendLogID = "go-test-only"
-	genOpts := func() Options {
-		return Options{
-			ServerURL:      httpsrv.URL,
-			HTTPTestClient: httpc,
-			//TimeNow:   s.control.TimeNow,
-			Logf: func(fmt string, args ...interface{}) {
-				t.Helper()
-				t.Logf("c1: "+fmt, args...)
-			},
-			Hostinfo: hi,
-		}
-	}
-
-	// Login with a new node key. This requires authorization.
-	c1, err := NewDirect(genOpts())
-	if err != nil {
-		t.Fatal(err)
-	}
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel()
-	authURL, err := c1.TryLogin(ctx, nil, 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	const user = "[email protected]"
-	postAuthURL(t, ctx, httpc, user, authURL)
-	newURL, err := c1.WaitLoginURL(ctx, authURL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if newURL != "" {
-		t.Fatalf("unexpected newURL: %s", newURL)
-	}
-
-	if err := c1.PollNetMap(ctx, 1, func(netMap *NetworkMap) {}); err != nil {
-		t.Fatal(err)
-	}
-
-	newPrivKey := func(t *testing.T) wgcfg.PrivateKey {
-		t.Helper()
-		k, err := wgcfg.NewPrivateKey()
-		if err != nil {
-			t.Fatal(err)
-		}
-		return k
-	}
-
-	// Replace the previous key with a new key.
-	persist1 := c1.GetPersist()
-	persist2 := Persist{
-		PrivateMachineKey: persist1.PrivateMachineKey,
-		OldPrivateNodeKey: persist1.PrivateNodeKey,
-		PrivateNodeKey:    newPrivKey(t),
-	}
-	opts := genOpts()
-	opts.Persist = persist2
-
-	c1, err = NewDirect(opts)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if authURL, err := c1.TryLogin(ctx, nil, 0); err != nil {
-		t.Fatal(err)
-	} else if authURL == "" {
-		t.Fatal("expected authURL for reused oldNodeKey, got none")
-	} else {
-		postAuthURL(t, ctx, httpc, user, authURL)
-		if newURL, err := c1.WaitLoginURL(ctx, authURL); err != nil {
-			t.Fatal(err)
-		} else if newURL != "" {
-			t.Fatalf("unexpected newURL: %s", newURL)
-		}
-	}
-	if p := c1.GetPersist(); p.PrivateNodeKey != opts.Persist.PrivateNodeKey {
-		t.Error("unexpected node key change")
-	} else {
-		persist2 = p
-	}
-
-	// Here we simulate a client using using old persistent data.
-	// We use the key we have already replaced as the old node key.
-	// This requires the user to authenticate.
-	persist3 := Persist{
-		PrivateMachineKey: persist1.PrivateMachineKey,
-		OldPrivateNodeKey: persist1.PrivateNodeKey,
-		PrivateNodeKey:    newPrivKey(t),
-	}
-	opts = genOpts()
-	opts.Persist = persist3
-
-	c1, err = NewDirect(opts)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if authURL, err := c1.TryLogin(ctx, nil, 0); err != nil {
-		t.Fatal(err)
-	} else if authURL == "" {
-		t.Fatal("expected authURL for reused oldNodeKey, got none")
-	} else {
-		postAuthURL(t, ctx, httpc, user, authURL)
-		if newURL, err := c1.WaitLoginURL(ctx, authURL); err != nil {
-			t.Fatal(err)
-		} else if newURL != "" {
-			t.Fatalf("unexpected newURL: %s", newURL)
-		}
-	}
-	if err := c1.PollNetMap(ctx, 1, func(netMap *NetworkMap) {}); err != nil {
-		t.Fatal(err)
-	}
-
-	// At this point, there should only be one node for the machine key
-	// registered as active in the server.
-	mkey := tailcfg.MachineKey(persist1.PrivateMachineKey.Public())
-	nodeIDs, err := server.DB().MachineNodes(mkey)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(nodeIDs) != 1 {
-		t.Logf("active nodes for machine key %v:", mkey)
-		for i, nodeID := range nodeIDs {
-			nodeKey := server.DB().NodeKey(nodeID)
-			t.Logf("\tnode %d: id=%v, key=%v", i, nodeID, nodeKey)
-		}
-		t.Fatalf("want 1 active node for the client machine, got %d", len(nodeIDs))
-	}
-
-	// Now try the previous node key. It should fail.
-	opts = genOpts()
-	opts.Persist = persist2
-	c1, err = NewDirect(opts)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// TODO(crawshaw): make this return an actual error.
-	// Have cfgdb track expired keys, and when an expired key is reused
-	// produce an error.
-	if authURL, err := c1.TryLogin(ctx, nil, 0); err != nil {
-		t.Fatal(err)
-	} else if authURL == "" {
-		t.Fatal("expected authURL for reused nodeKey, got none")
-	} else {
-		postAuthURL(t, ctx, httpc, user, authURL)
-		if newURL, err := c1.WaitLoginURL(ctx, authURL); err != nil {
-			t.Fatal(err)
-		} else if newURL != "" {
-			t.Fatalf("unexpected newURL: %s", newURL)
-		}
-	}
-	if err := c1.PollNetMap(ctx, 1, func(netMap *NetworkMap) {}); err != nil {
-		t.Fatal(err)
-	}
-	if nodeIDs, err := server.DB().MachineNodes(mkey); err != nil {
-		t.Fatal(err)
-	} else if len(nodeIDs) != 1 {
-		t.Fatalf("want 1 active node for the client machine, got %d", len(nodeIDs))
-	}
-}