github.com/sercand/please@v13.4.0+incompatible/src/cache/rpc_cache_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"os"
     5  	"path"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"google.golang.org/grpc"
    13  
    14  	"github.com/thought-machine/please/src/core"
    15  	"github.com/thought-machine/please/tools/cache/server"
    16  )
    17  
    18  var (
    19  	label    core.BuildLabel
    20  	rpccache *rpcCache
    21  )
    22  
    23  func init() {
    24  	runtime.GOMAXPROCS(1) // Don't allow tests to run in parallel, they should work but makes debugging tricky
    25  	label = core.NewBuildLabel("pkg/name", "label_name")
    26  
    27  	// Move this directory from test_data to somewhere local.
    28  	// This is easier than changing our working dir & a better test of some things too.
    29  	if err := os.Rename("src/cache/test_data/plz-out", "plz-out"); err != nil {
    30  		log.Fatalf("Failed to prepare test directory: %s\n", err)
    31  	}
    32  
    33  	_, addr := startServer("", "", "")
    34  	rpccache = buildClient(addr, "")
    35  }
    36  
    37  func startServer(keyFile, certFile, caCertFile string) (*grpc.Server, string) {
    38  	// Arbitrary large numbers so the cleaner never needs to run.
    39  	cache := server.NewCache("src/cache/test_data", 20*time.Hour, 100000, 100000000, 1000000000)
    40  	s, lis := server.BuildGrpcServer(0, cache, nil, keyFile, certFile, caCertFile, "", "")
    41  	go s.Serve(lis)
    42  	return s, lis.Addr().String()
    43  }
    44  
    45  func buildClient(addr, ca string) *rpcCache {
    46  	config := core.DefaultConfiguration()
    47  	if err := config.Cache.RPCURL.UnmarshalFlag(strings.Replace(addr, "[::]", "localhost", 1)); err != nil {
    48  		log.Fatalf("%s", err)
    49  	}
    50  	config.Cache.RPCWriteable = true
    51  	config.Cache.RPCCACert = ca
    52  
    53  	cache, err := newRPCCache(config)
    54  	if err != nil {
    55  		log.Fatalf("Failed to create RPC cache: %s", err)
    56  	}
    57  
    58  	// Busy-wait sucks but this isn't supposed to be visible from outside.
    59  	for i := 0; i < 10 && !cache.Connected && cache.Connecting; i++ {
    60  		time.Sleep(100 * time.Millisecond)
    61  	}
    62  	return cache
    63  }
    64  
    65  func TestStore(t *testing.T) {
    66  	target := core.NewBuildTarget(label)
    67  	target.AddOutput("testfile2")
    68  	rpccache.Store(target, []byte("test_key"))
    69  	expectedPath := path.Join("src/cache/test_data", core.OsArch, "pkg/name", "label_name", "dGVzdF9rZXk", target.Outputs()[0])
    70  	if !core.PathExists(expectedPath) {
    71  		t.Errorf("Test file %s was not stored in cache.", expectedPath)
    72  	}
    73  }
    74  
    75  func TestRetrieve(t *testing.T) {
    76  	target := core.NewBuildTarget(label)
    77  	target.AddOutput("testfile")
    78  	if !rpccache.Retrieve(target, []byte("test_key")) {
    79  		t.Error("Artifact expected and not found.")
    80  	}
    81  }
    82  
    83  func TestStoreAndRetrieve(t *testing.T) {
    84  	target := core.NewBuildTarget(label)
    85  	target.AddOutput("testfile3")
    86  	rpccache.Store(target, []byte("test_key"))
    87  	// Remove the file so we can test retrieval correctly
    88  	outPath := path.Join(target.OutDir(), target.Outputs()[0])
    89  	if err := os.Remove(outPath); err != nil {
    90  		t.Errorf("Failed to remove artifact: %s", err)
    91  	}
    92  	if !rpccache.Retrieve(target, []byte("test_key")) {
    93  		t.Error("Artifact expected and not found.")
    94  	} else if !core.PathExists(outPath) {
    95  		t.Errorf("Artifact %s doesn't exist after alleged cache retrieval", outPath)
    96  	}
    97  }
    98  
    99  func TestClean(t *testing.T) {
   100  	target := core.NewBuildTarget(label)
   101  	rpccache.Clean(target)
   102  	filename := path.Join("src/cache/test_data", core.OsArch, "pkg/name/label_name")
   103  	if core.PathExists(filename) {
   104  		t.Errorf("File %s was not removed from cache.", filename)
   105  	}
   106  }
   107  
   108  func TestDisconnectAfterEnoughErrors(t *testing.T) {
   109  	// Need a separate cache for this so we don't interfere with the other tests.
   110  	s, addr := startServer("", "", "")
   111  	c := buildClient(addr, "")
   112  
   113  	target := core.NewBuildTarget(label)
   114  	target.AddOutput("testfile4")
   115  	key := []byte("test_key")
   116  	c.Store(target, []byte("test_key"))
   117  	assert.True(t, c.Retrieve(target, key))
   118  	s.Stop()
   119  	// Now after we hit the max number of errors it should disconnect.
   120  	for i := 0; i < maxErrors; i++ {
   121  		assert.True(t, c.Connected)
   122  		assert.False(t, c.Retrieve(target, key))
   123  	}
   124  	assert.False(t, c.Connected)
   125  }
   126  
   127  func TestLoadCertificates(t *testing.T) {
   128  	_, err := loadAuth("", "src/cache/test_data/cert.pem", "src/cache/test_data/key.pem")
   129  	assert.NoError(t, err, "Trivial case with PEM files already")
   130  	_, err = loadAuth("", "id_rsa.pub", "id_rsa")
   131  	assert.Error(t, err, "Fails because files don't exist")
   132  }
   133  
   134  func TestRetrieveSSL(t *testing.T) {
   135  	// Need a separate cache for this so we don't interfere with the other tests.
   136  	s, addr := startServer("src/cache/test_data/key.pem", "src/cache/test_data/cert_signed.pem", "src/cache/test_data/ca.pem")
   137  	defer s.Stop()
   138  	c := buildClient(addr, "")
   139  	assert.False(t, c.Connected, "Should fail to connect without giving the client a CA cert")
   140  	c = buildClient(addr, "src/cache/test_data/ca.pem")
   141  	assert.True(t, c.Connected, "Connects OK this time")
   142  }