carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "context"
5 "crypto/ed25519"
6 "errors"
7 "fmt"
8 "strings"
9 "sync"
10 "testing"
11 "time"
12
13 "github.com/carlosframework/platform/internal/hostactors"
14 "github.com/carlosframework/platform/internal/hostops"
15 "github.com/carlosframework/platform/internal/release"
16)
17
18// noMembers is a membership reader that is never asked.
19type noMembers struct{}
20
21func (noMembers) Member(context.Context, string, string) (hostactors.Membership, error) {
22 return hostactors.Membership{}, errors.New("not asked")
23}
24
25func TestEnrollPassIsBuiltFromTheClaimAuthority(t *testing.T) {
26 pub, key, _ := ed25519.GenerateKey(nil)
27 a := &hostops.ProductionAuthority{Directory: hostactors.Directory{Store: release.NewDirStore(t.TempDir()), PublicKey: pub, Bucket: "bucket"},
28 Signer: release.RootSigner(key), Namespace: "platform"}
29 if _, err := newAutoEnroller(nil, noMembers{}); !errors.Is(err, hostops.ErrContract) {
30 t.Fatalf("no authority: %v", err)
31 }
32 if _, err := newAutoEnroller(a, nil); !errors.Is(err, hostops.ErrContract) {
33 t.Fatalf("no membership reader: %v", err)
34 }
35 e, err := newAutoEnroller(a, noMembers{})
36 if err != nil {
37 t.Fatal(err)
38 }
39 if e.Namespace != "platform" || e.Pool != "default" || e.Patience != enrollPatience || len(e.Certs) == 0 || e.Directory.Bucket != "bucket" || e.Members != (noMembers{}) || e.Logf == nil {
40 t.Fatalf("enroller %+v", e)
41 }
42}
43
44// A pass that cannot read the roster is logged on its first failure and
45// every tenth, not every ten seconds, and the loop ends with its context.
46func TestEnrollPassLogsFailuresSparingly(t *testing.T) {
47 pub, key, _ := ed25519.GenerateKey(nil)
48 e := &hostactors.AutoEnroller{Directory: hostactors.Directory{Store: release.NewDirStore(t.TempDir()), PublicKey: pub, Bucket: "bucket"},
49 Signer: release.RootSigner(key), Namespace: "platform", Pool: "default", Now: time.Now, Patience: time.Minute}
50 var mu sync.Mutex
51 var lines []string
52 logf := func(format string, args ...any) {
53 mu.Lock()
54 lines = append(lines, fmt.Sprintf(format, args...))
55 mu.Unlock()
56 }
57 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
58 defer cancel()
59 runEnrollPass(ctx, e, 2*time.Millisecond, logf)
60 mu.Lock()
61 defer mu.Unlock()
62 if len(lines) < 2 || !strings.Contains(lines[0], "armed") {
63 t.Fatalf("lines %q", lines)
64 }
65 for i, l := range lines[1:] {
66 var n int
67 if _, err := fmt.Sscanf(l[strings.Index(l, "#"):], "#%d", &n); err != nil || (n != 1 && n%10 != 0) || (i == 0 && n != 1) {
68 t.Fatalf("logged %q", l)
69 }
70 }
71}
72