package release import ( "bytes" "context" "errors" "strings" "testing" ) func TestManifestDigestIsTheStoredBytes(t *testing.T) { s := NewDirStore(t.TempDir()) ctx := context.Background() shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("bin one")) raw, _, err := s.Get(ctx, ManifestKey("bab", "km", "v1")) if err != nil { t.Fatal(err) } m, got, err := GetManifestRaw(ctx, s, "bab", "km", "v1") if err != nil || m.Version != "v1" || !bytes.Equal(got, raw) { t.Fatalf("GetManifestRaw = %+v, %q, %v; want the stored bytes", m, got, err) } if d := ManifestDigest(raw); d != etagOf(raw) || !validDigest(d) { t.Fatalf("ManifestDigest = %q, want the hex sha256 of the stored bytes", d) } } func TestCheckManifestDigest(t *testing.T) { s := NewDirStore(t.TempDir()) ctx := context.Background() shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("bin one")) raw, _, _ := s.Get(ctx, ManifestKey("bab", "km", "v1")) want := ManifestDigest(raw) if m, _, err := CheckManifestDigest(ctx, s, "bab", "km", "v1", want); err != nil || m == nil { t.Fatalf("matching digest: %v", err) } if _, _, err := CheckManifestDigest(ctx, s, "bab", "km", "v1", ""); err != nil { t.Fatalf("no digest asked for: %v", err) } other := ManifestDigest([]byte("some other manifest")) if _, _, err := CheckManifestDigest(ctx, s, "bab", "km", "v1", other); !errors.Is(err, ErrManifestDigest) { t.Fatalf("mismatched digest: %v, want ErrManifestDigest", err) } } func TestValidDigest(t *testing.T) { for d, ok := range map[string]bool{ ManifestDigest([]byte("x")): true, "": false, "ABCDEF" + ManifestDigest([]byte("x"))[6:]: false, // upper case is not canonical ManifestDigest([]byte("x"))[:63]: false, } { if validDigest(d) != ok { t.Errorf("validDigest(%q) = %v, want %v", d, !ok, ok) } } } // failingGetStore fails every Get of one key, as a transient bucket error // would, while listing still names it. type failingGetStore struct { Store key string } var errTransient = errors.New("transient read failure") func (f failingGetStore) Get(ctx context.Context, key string) ([]byte, string, error) { if key == f.key { return nil, "", errTransient } return f.Store.Get(ctx, key) } // Astra r1 #4: a channel whose pointer cannot be read is not skipped. It // comes back with Err set, so no consumer can count it as carrying digests. func TestDigestReportMarksAChannelItCannotRead(t *testing.T) { base := NewDirStore(t.TempDir()) ctx := context.Background() priv, pub := testKeys(t) shipRelease(t, base, "bab", "km", "v1", adoptPlatform, []byte("one")) if err := Promote(ctx, base, priv, "bab", "km", "beta", "v1"); err != nil { // no digests t.Fatal(err) } markerOn(t, base, priv, "bab") if err := Promote(ctx, base, priv, "bab", "km", "canary/x", "v1"); err != nil { // digests t.Fatal(err) } s := failingGetStore{Store: base, key: ChannelKey("bab", "km", "beta")} rows, _, err := DigestReport(ctx, s, pub, "bab", "km") if err != nil || len(rows) != 2 { t.Fatalf("report = %+v, %v; want both channels", rows, err) } got := map[string]ChannelDigestState{} for _, r := range rows { got[r.Channel] = r } if b := got["beta"]; b.Err == "" || !strings.Contains(b.Err, errTransient.Error()) || b.HeadDigest { t.Fatalf("beta = %+v; want its read error, never a digest state", b) } if c := got["canary/x"]; c.Err != "" || !c.HeadDigest { t.Fatalf("canary/x = %+v; want it read as carrying digests", c) } }