metropolis/test/util: move TestCurator to utils package

To use it inside other tests this change moves the TestCurator
to allow usage inside other tests

Change-Id: I75be31f490eb84e5c9bc56b65317ea5483415dcf
Reviewed-on: https://review.monogon.dev/c/monogon/+/1954
Reviewed-by: Serge Bazanski <serge@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/node/core/clusternet/BUILD.bazel b/metropolis/node/core/clusternet/BUILD.bazel
index 35e6903..a5fc41a 100644
--- a/metropolis/node/core/clusternet/BUILD.bazel
+++ b/metropolis/node/core/clusternet/BUILD.bazel
@@ -41,11 +41,9 @@
         "//metropolis/pkg/event/memory",
         "//metropolis/pkg/supervisor",
         "//metropolis/proto/common",
+        "//metropolis/test/util",
         "@com_zx2c4_golang_wireguard_wgctrl//:wgctrl",
         "@com_zx2c4_golang_wireguard_wgctrl//wgtypes",
-        "@org_golang_google_grpc//:go_default_library",
-        "@org_golang_google_grpc//credentials/insecure",
-        "@org_golang_google_grpc//test/bufconn",
     ],
 )
 
diff --git a/metropolis/node/core/clusternet/clusternet_test.go b/metropolis/node/core/clusternet/clusternet_test.go
index 509678b..bda1459 100644
--- a/metropolis/node/core/clusternet/clusternet_test.go
+++ b/metropolis/node/core/clusternet/clusternet_test.go
@@ -1,7 +1,6 @@
 package clusternet
 
 import (
-	"context"
 	"fmt"
 	"net"
 	"os"
@@ -12,9 +11,6 @@
 
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials/insecure"
-	"google.golang.org/grpc/test/bufconn"
 
 	common "source.monogon.dev/metropolis/node"
 	"source.monogon.dev/metropolis/node/core/localstorage"
@@ -22,101 +18,11 @@
 	"source.monogon.dev/metropolis/node/core/network"
 	"source.monogon.dev/metropolis/pkg/event/memory"
 	"source.monogon.dev/metropolis/pkg/supervisor"
+	"source.monogon.dev/metropolis/test/util"
 
 	apb "source.monogon.dev/metropolis/node/core/curator/proto/api"
-	cpb "source.monogon.dev/metropolis/proto/common"
 )
 
-// testCurator is a shim Curator implementation that serves pending Watch
-// requests based on data submitted to a channel.
-type testCurator struct {
-	apb.UnimplementedCuratorServer
-
-	watchC    chan *apb.WatchEvent
-	updateReq memory.Value[*apb.UpdateNodeClusterNetworkingRequest]
-}
-
-// Watch implements a minimum Watch which just returns all nodes at once.
-func (t *testCurator) Watch(_ *apb.WatchRequest, srv apb.Curator_WatchServer) error {
-	ctx := srv.Context()
-	for {
-		select {
-		case <-ctx.Done():
-			return ctx.Err()
-		case ev := <-t.watchC:
-			if err := srv.Send(ev); err != nil {
-				return err
-			}
-		}
-	}
-}
-
-func (t *testCurator) UpdateNodeClusterNetworking(ctx context.Context, req *apb.UpdateNodeClusterNetworkingRequest) (*apb.UpdateNodeClusterNetworkingResponse, error) {
-	t.updateReq.Set(req)
-	return &apb.UpdateNodeClusterNetworkingResponse{}, nil
-}
-
-// nodeWithPrefix submits a given node/key/address with prefixes to the Watch
-// event channel.
-func (t *testCurator) nodeWithPrefixes(key wgtypes.Key, id, address string, prefixes ...string) {
-	var p []*cpb.NodeClusterNetworking_Prefix
-	for _, prefix := range prefixes {
-		p = append(p, &cpb.NodeClusterNetworking_Prefix{Cidr: prefix})
-	}
-	n := &apb.Node{
-		Id: id,
-		Status: &cpb.NodeStatus{
-			ExternalAddress: address,
-		},
-		Clusternet: &cpb.NodeClusterNetworking{
-			WireguardPubkey: key.PublicKey().String(),
-			Prefixes:        p,
-		},
-	}
-	t.watchC <- &apb.WatchEvent{
-		Nodes: []*apb.Node{
-			n,
-		},
-	}
-}
-
-// deleteNode submits a given node for deletion to the Watch event channel.
-func (t *testCurator) deleteNode(id string) {
-	t.watchC <- &apb.WatchEvent{
-		NodeTombstones: []*apb.WatchEvent_NodeTombstone{
-			{
-				NodeId: id,
-			},
-		},
-	}
-}
-
-// makeTestCurator returns a working testCurator alongside a grpc connection to
-// it.
-func makeTestCurator(t *testing.T) (*testCurator, *grpc.ClientConn) {
-	cur := &testCurator{
-		watchC: make(chan *apb.WatchEvent),
-	}
-
-	srv := grpc.NewServer()
-	apb.RegisterCuratorServer(srv, cur)
-	externalLis := bufconn.Listen(1024 * 1024)
-	go func() {
-		if err := srv.Serve(externalLis); err != nil {
-			t.Fatalf("GRPC serve failed: %v", err)
-		}
-	}()
-	withLocalDialer := grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
-		return externalLis.Dial()
-	})
-	cl, err := grpc.Dial("local", withLocalDialer, grpc.WithTransportCredentials(insecure.NewCredentials()))
-	if err != nil {
-		t.Fatalf("Dialing GRPC failed: %v", err)
-	}
-
-	return cur, cl
-}
-
 // fakeWireguard implements wireguard while keeping peer information internally.
 type fakeWireguard struct {
 	k wgtypes.Key
@@ -177,7 +83,7 @@
 		t.Fatalf("Failed to generate private key: %v", err)
 	}
 
-	cur, cl := makeTestCurator(t)
+	cur, cl := util.MakeTestCurator(t)
 	defer cl.Close()
 	curator := apb.NewCuratorClient(cl)
 
@@ -245,7 +151,7 @@
 	}
 
 	// Start with a single node.
-	cur.nodeWithPrefixes(key1, "metropolis-fake-1", "1.2.3.4")
+	cur.NodeWithPrefixes(key1, "metropolis-fake-1", "1.2.3.4")
 	assertStateEventual(map[string]*node{
 		"metropolis-fake-1": {
 			pubkey:   key1.PublicKey().String(),
@@ -254,7 +160,7 @@
 		},
 	})
 	// Change the node's peer address.
-	cur.nodeWithPrefixes(key1, "metropolis-fake-1", "1.2.3.5")
+	cur.NodeWithPrefixes(key1, "metropolis-fake-1", "1.2.3.5")
 	assertStateEventual(map[string]*node{
 		"metropolis-fake-1": {
 			pubkey:   key1.PublicKey().String(),
@@ -263,7 +169,7 @@
 		},
 	})
 	// Add another node.
-	cur.nodeWithPrefixes(key2, "metropolis-fake-2", "1.2.3.6")
+	cur.NodeWithPrefixes(key2, "metropolis-fake-2", "1.2.3.6")
 	assertStateEventual(map[string]*node{
 		"metropolis-fake-1": {
 			pubkey:   key1.PublicKey().String(),
@@ -280,8 +186,8 @@
 	wg.muNodes.Lock()
 	wg.failNextUpdate = true
 	wg.muNodes.Unlock()
-	cur.nodeWithPrefixes(key1, "metropolis-fake-1", "1.2.3.5", "10.100.10.0/24", "10.100.20.0/24")
-	cur.nodeWithPrefixes(key2, "metropolis-fake-2", "1.2.3.6", "10.100.30.0/24", "10.100.40.0/24")
+	cur.NodeWithPrefixes(key1, "metropolis-fake-1", "1.2.3.5", "10.100.10.0/24", "10.100.20.0/24")
+	cur.NodeWithPrefixes(key2, "metropolis-fake-2", "1.2.3.6", "10.100.30.0/24", "10.100.40.0/24")
 	assertStateEventual(map[string]*node{
 		"metropolis-fake-1": {
 			pubkey:  key1.PublicKey().String(),
@@ -299,7 +205,7 @@
 		},
 	})
 	// Delete one of the nodes.
-	cur.deleteNode("metropolis-fake-1")
+	cur.DeleteNode("metropolis-fake-1")
 	assertStateEventual(map[string]*node{
 		"metropolis-fake-2": {
 			pubkey:  key2.PublicKey().String(),