keel/approvals/approvals_test.go

367 lines
8.7 KiB
Go

package approvals
import (
"context"
"testing"
"time"
"github.com/keel-hq/keel/cache/memory"
"github.com/keel-hq/keel/types"
"github.com/keel-hq/keel/util/codecs"
)
func TestCreateApproval(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(5 * time.Minute),
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
stored, err := am.Get("xxx/app-1")
if err != nil {
t.Fatalf("failed to get approval: %s", err)
}
if stored.CurrentVersion != "1.2.3" {
t.Errorf("unexpected version: %s", stored.CurrentVersion)
}
}
func TestDeleteApproval(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(5 * time.Minute),
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
err = am.Delete("xxx/app-1")
if err != nil {
t.Errorf("failed to delete approval: %s", err)
}
_, err = am.Get("xxx/app-1")
if err == nil {
t.Errorf("expected to get an error when retrieving deleted approval")
}
}
func TestUpdateApproval(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
VotesRequired: 1,
VotesReceived: 0,
Deadline: time.Now().Add(5 * time.Minute),
Event: &types.Event{
Repository: types.Repository{
Name: "very/repo",
Tag: "1.2.5",
},
},
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ch, err := am.SubscribeApproved(ctx)
if err != nil {
t.Fatalf("failed to subscribe: %s", err)
}
err = am.Update(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
VotesRequired: 1,
VotesReceived: 1,
Deadline: time.Now().Add(5 * time.Minute),
Event: &types.Event{
Repository: types.Repository{
Name: "very/repo",
Tag: "1.2.5",
},
},
})
approved := <-ch
if approved.Event.Repository.Name != "very/repo" {
t.Errorf("unexpected repo name in re-submitted event: %s", approved.Event.Repository.Name)
}
if approved.Event.Repository.Tag != "1.2.5" {
t.Errorf("unexpected repo tag in re-submitted event: %s", approved.Event.Repository.Tag)
}
}
func TestUpdateApprovalRejected(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
VotesRequired: 1,
VotesReceived: 0,
Deadline: time.Now().Add(5 * time.Minute),
Event: &types.Event{
Repository: types.Repository{
Name: "very/repo",
Tag: "1.2.5",
},
},
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ch, err := am.SubscribeApproved(ctx)
if err != nil {
t.Fatalf("failed to subscribe: %s", err)
}
// rejecting
err = am.Update(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
VotesRequired: 1,
VotesReceived: 0,
Rejected: true,
Deadline: time.Now().Add(5 * time.Minute),
Event: &types.Event{
Repository: types.Repository{
Name: "very/repo",
Tag: "1.2.5",
},
},
})
if err != nil {
t.Fatalf("failed to update approval: %s", err)
}
// sending vote
err = am.Update(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
VotesRequired: 1,
VotesReceived: 1,
Rejected: true,
Deadline: time.Now().Add(5 * time.Minute),
Event: &types.Event{
Repository: types.Repository{
Name: "very/repo",
Tag: "1.2.5",
},
},
})
if err != nil {
t.Fatalf("failed to update approval: %s", err)
}
select {
case <-time.After(500 * time.Millisecond):
// success
return
case approval := <-ch:
t.Errorf("unexpected approval got: %s", approval.Identifier)
}
}
func TestApprove(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1:1.2.5",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(5 * time.Minute),
VotesRequired: 2,
VotesReceived: 0,
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
am.Approve("xxx/app-1:1.2.5", "warda")
stored, err := am.Get("xxx/app-1:1.2.5")
if err != nil {
t.Fatalf("failed to get approval: %s", err)
}
if stored.VotesReceived != 1 {
t.Errorf("unexpected number of received votes: %d", stored.VotesReceived)
}
}
func TestApproveTwiceSameVoter(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1:1.2.5",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(5 * time.Minute),
VotesRequired: 2,
VotesReceived: 0,
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
am.Approve("xxx/app-1:1.2.5", "warda")
am.Approve("xxx/app-1:1.2.5", "warda")
stored, err := am.Get("xxx/app-1:1.2.5")
if err != nil {
t.Fatalf("failed to get approval: %s", err)
}
// should still be the same
if stored.VotesReceived != 1 {
t.Errorf("unexpected number of received votes: %d", stored.VotesReceived)
}
}
func TestApproveTwoVoters(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1:1.2.5",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(5 * time.Minute),
VotesRequired: 2,
VotesReceived: 0,
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
am.Approve("xxx/app-1:1.2.5", "w")
am.Approve("xxx/app-1:1.2.5", "k")
stored, err := am.Get("xxx/app-1:1.2.5")
if err != nil {
t.Fatalf("failed to get approval: %s", err)
}
// should still be the same
if stored.VotesReceived != 2 {
t.Errorf("unexpected number of received votes: %d", stored.VotesReceived)
}
}
func TestReject(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(5 * time.Minute),
VotesRequired: 2,
VotesReceived: 0,
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
am.Reject("xxx/app-1")
stored, err := am.Get("xxx/app-1")
if err != nil {
t.Fatalf("failed to get approval: %s", err)
}
if !stored.Rejected {
t.Errorf("unexpected approval to be rejected")
}
}
func TestExpire(t *testing.T) {
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
am := New(mem, codecs.DefaultSerializer())
err := am.Create(&types.Approval{
Provider: types.ProviderTypeKubernetes,
Identifier: "xxx/app-1",
CurrentVersion: "1.2.3",
NewVersion: "1.2.5",
Deadline: time.Now().Add(-5 * time.Minute),
VotesRequired: 2,
VotesReceived: 0,
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
err = am.expireEntries()
if err != nil {
t.Errorf("got error while expiring entries: %s", err)
}
_, err = am.Get("xxx/app-1")
if err == nil {
t.Errorf("expected approval to be deleted but didn't get an error")
}
}