source-controller/internal/index/digest_test.go

382 lines
7.5 KiB
Go

/*
Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package index
import (
"bytes"
"errors"
"testing"
. "github.com/onsi/gomega"
"github.com/opencontainers/go-digest"
)
func TestWithIndex(t *testing.T) {
t.Run("sets the index", func(t *testing.T) {
g := NewWithT(t)
i := map[string]string{"foo": "bar"}
d := &Digester{}
WithIndex(i)(d)
g.Expect(d.index).To(Equal(i))
})
t.Run("resets the digests", func(t *testing.T) {
g := NewWithT(t)
i := map[string]string{"foo": "bar"}
d := &Digester{
digests: map[digest.Algorithm]digest.Digest{
digest.SHA256: "sha256:foo",
},
}
WithIndex(i)(d)
g.Expect(d.digests).To(BeEmpty())
})
t.Run("handles nil index", func(t *testing.T) {
g := NewWithT(t)
d := &Digester{}
WithIndex(nil)(d)
g.Expect(d.index).To(BeNil())
})
}
func TestNewDigester(t *testing.T) {
t.Run("default", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
g.Expect(d).ToNot(BeNil())
g.Expect(d.index).ToNot(BeNil())
g.Expect(d.digests).ToNot(BeNil())
})
t.Run("with index", func(t *testing.T) {
g := NewWithT(t)
i := map[string]string{"foo": "bar"}
d := NewDigester(WithIndex(i))
g.Expect(d).ToNot(BeNil())
g.Expect(d.index).To(Equal(i))
g.Expect(d.digests).ToNot(BeNil())
})
}
func TestDigester_Add(t *testing.T) {
t.Run("adds", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Add("foo", "bar")
g.Expect(d.index).To(HaveKeyWithValue("foo", "bar"))
})
t.Run("overwrites", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Add("foo", "bar")
d.Add("foo", "baz")
g.Expect(d.index).To(HaveKeyWithValue("foo", "baz"))
})
t.Run("resets digests", func(t *testing.T) {
g := NewWithT(t)
d := &Digester{
index: map[string]string{},
digests: map[digest.Algorithm]digest.Digest{
digest.SHA256: "sha256:foo",
},
}
d.Add("foo", "bar")
g.Expect(d.digests).To(BeEmpty())
})
t.Run("adds empty key and value", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Add("", "")
g.Expect(d.index).To(HaveKeyWithValue("", ""))
})
}
func TestDigester_Delete(t *testing.T) {
t.Run("deletes", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Add("foo", "bar")
d.Delete("foo")
g.Expect(d.index).ToNot(HaveKey("foo"))
})
t.Run("resets digests", func(t *testing.T) {
g := NewWithT(t)
d := &Digester{
index: map[string]string{
"foo": "bar",
},
digests: map[digest.Algorithm]digest.Digest{
digest.SHA256: "sha256:foo",
},
}
d.Delete("nop")
g.Expect(d.digests).To(HaveLen(1))
d.Delete("foo")
g.Expect(d.digests).To(BeEmpty())
})
t.Run("deletes non-existent key without error", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Delete("non-existent")
g.Expect(d.index).To(BeEmpty())
g.Expect(d.digests).To(BeEmpty())
})
}
func TestDigester_Get(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Add("foo", "bar")
g.Expect(d.Get("foo")).To(Equal("bar"))
g.Expect(d.Get("bar")).To(BeEmpty())
}
func TestDigester_Has(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.Add("foo", "bar")
g.Expect(d.Has("foo")).To(BeTrue())
g.Expect(d.Has("bar")).To(BeFalse())
}
func TestDigester_Index(t *testing.T) {
t.Run("returns a copy of the index", func(t *testing.T) {
g := NewWithT(t)
i := map[string]string{
"foo": "bar",
"bar": "baz",
}
d := NewDigester(WithIndex(i))
iCopy := d.Index()
g.Expect(iCopy).To(Equal(i))
g.Expect(iCopy).ToNot(BeIdenticalTo(i))
})
t.Run("returns an empty copy for an empty index", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
emptyIndex := d.Index()
g.Expect(emptyIndex).To(BeEmpty())
})
}
func TestDigester_Len(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"foo": "bar",
"bar": "baz",
}))
g.Expect(d.Len()).To(Equal(2))
g.Expect(NewDigester().Len()).To(Equal(0))
}
func TestDigester_String(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"foo": "bar",
"bar": "baz",
}))
g.Expect(d.String()).To(Equal(`bar baz
foo bar
`))
g.Expect(NewDigester().String()).To(Equal(""))
}
func TestDigester_WriteTo(t *testing.T) {
t.Run("writes", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"foo": "bar",
"bar": "baz",
}))
expect := `bar baz
foo bar
`
var buf bytes.Buffer
n, err := d.WriteTo(&buf)
g.Expect(n).To(Equal(int64(len(expect))))
g.Expect(err).ToNot(HaveOccurred())
g.Expect(buf.String()).To(Equal(expect))
})
t.Run("errors", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"foo": "bar",
"bar": "baz",
}))
w := &fakeWriter{
err: errors.New("write error"),
written: 5,
}
n, err := d.WriteTo(w)
g.Expect(err).To(HaveOccurred())
g.Expect(errors.Is(err, w.err)).To(BeTrue())
g.Expect(n).To(Equal(int64(w.written)))
})
}
func TestDigester_Digest(t *testing.T) {
t.Run("returns digest", func(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"foo": "bar",
"bar": "baz",
}))
expect := digest.SHA256.FromString(d.String())
g.Expect(d.Digest(digest.SHA256)).To(Equal(expect))
g.Expect(d.digests).To(HaveKeyWithValue(digest.SHA256, expect))
})
t.Run("returns cached digest", func(t *testing.T) {
g := NewWithT(t)
d := &Digester{
index: map[string]string{
"foo": "bar",
"bar": "baz",
},
digests: map[digest.Algorithm]digest.Digest{
digest.SHA256: "sha256:foo",
},
}
g.Expect(d.Digest(digest.SHA256)).To(Equal(d.digests[digest.SHA256]))
})
}
func TestDigester_Verify(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"foo": "bar",
}))
g.Expect(d.Verify(d.Digest(digest.SHA256))).To(BeTrue())
g.Expect(d.Verify(digest.SHA256.FromString("different"))).To(BeFalse())
}
func TestDigester_sortedKeys(t *testing.T) {
g := NewWithT(t)
d := NewDigester(WithIndex(map[string]string{
"c/d/e": "bar",
"a/b/c": "baz",
"f/g/h": "foo",
}))
g.Expect(d.sortedKeys()).To(Equal([]string{
"a/b/c",
"c/d/e",
"f/g/h",
}))
}
func TestDigester_reset(t *testing.T) {
g := NewWithT(t)
d := NewDigester()
d.digests = map[digest.Algorithm]digest.Digest{
digest.SHA256: "sha256:foo",
}
d.reset()
g.Expect(d.digests).To(BeEmpty())
}
func Test_writeLine(t *testing.T) {
t.Run("writes", func(t *testing.T) {
g := NewWithT(t)
var buf bytes.Buffer
n, err := writeLine(&buf, "foo", "bar")
g.Expect(n).To(Equal(8))
g.Expect(err).ToNot(HaveOccurred())
g.Expect(buf.String()).To(Equal(`foo bar
`))
})
t.Run("errors", func(t *testing.T) {
g := NewWithT(t)
w := &fakeWriter{
err: errors.New("write error"),
written: 5,
}
n, err := writeLine(w, "foo", "bar")
g.Expect(err).To(HaveOccurred())
g.Expect(errors.Is(err, w.err)).To(BeTrue())
g.Expect(n).To(Equal(w.written))
})
}
type fakeWriter struct {
written int
err error
}
func (f *fakeWriter) Write(p []byte) (n int, err error) {
return f.written, f.err
}