432 lines
12 KiB
Go
432 lines
12 KiB
Go
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
// Use of this source code is governed by the Drone Non-Commercial License
|
|
// that can be found in the LICENSE file.
|
|
|
|
package build
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"testing"
|
|
|
|
"github.com/drone/drone/core"
|
|
"github.com/drone/drone/store/shared/db"
|
|
|
|
"github.com/drone/drone/store/shared/db/dbtest"
|
|
)
|
|
|
|
var noContext = context.TODO()
|
|
|
|
func TestBuild(t *testing.T) {
|
|
conn, err := dbtest.Connect()
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
defer func() {
|
|
dbtest.Reset(conn)
|
|
dbtest.Disconnect(conn)
|
|
}()
|
|
|
|
store := New(conn).(*buildStore)
|
|
t.Run("Create", testBuildCreate(store))
|
|
t.Run("Purge", testBuildPurge(store))
|
|
t.Run("Count", testBuildCount(store))
|
|
t.Run("Pending", testBuildPending(store))
|
|
t.Run("Running", testBuildRunning(store))
|
|
t.Run("Latest", testBuildLatest(store))
|
|
}
|
|
|
|
func testBuildCreate(store *buildStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
build := &core.Build{
|
|
RepoID: 1,
|
|
Number: 99,
|
|
Event: core.EventPush,
|
|
Ref: "refs/heads/master",
|
|
Target: "master",
|
|
}
|
|
stage := &core.Stage{
|
|
RepoID: 42,
|
|
Number: 1,
|
|
}
|
|
err := store.Create(noContext, build, []*core.Stage{stage})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if build.ID == 0 {
|
|
t.Errorf("Want build ID assigned, got %d", build.ID)
|
|
}
|
|
if got, want := build.Version, int64(1); got != want {
|
|
t.Errorf("Want build Version %d, got %d", want, got)
|
|
}
|
|
t.Run("Find", testBuildFind(store, build))
|
|
t.Run("FindNumber", testBuildFindNumber(store, build))
|
|
t.Run("FindRef", testBuildFindRef(store, build))
|
|
t.Run("List", testBuildList(store, build))
|
|
t.Run("ListRef", testBuildListRef(store, build))
|
|
t.Run("Update", testBuildUpdate(store, build))
|
|
t.Run("Locking", testBuildLocking(store, build))
|
|
t.Run("Delete", testBuildDelete(store, build))
|
|
}
|
|
}
|
|
|
|
func testBuildFind(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
result, err := store.Find(noContext, build.ID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
t.Run("Fields", testBuild(result))
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildFindNumber(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
item, err := store.FindNumber(noContext, build.RepoID, build.Number)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
t.Run("Fields", testBuild(item))
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildFindRef(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
item, err := store.FindRef(noContext, build.RepoID, build.Ref)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
t.Run("Fields", testBuild(item))
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildList(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
list, err := store.List(noContext, build.RepoID, 10, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if got, want := len(list), 1; got != want {
|
|
t.Errorf("Want list count %d, got %d", want, got)
|
|
} else {
|
|
t.Run("Fields", testBuild(list[0]))
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildListRef(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
list, err := store.ListRef(noContext, build.RepoID, build.Ref, 10, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if got, want := len(list), 1; got != want {
|
|
t.Errorf("Want list count %d, got %d", want, got)
|
|
} else {
|
|
t.Run("Fields", testBuild(list[0]))
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildUpdate(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
before := &core.Build{
|
|
ID: build.ID,
|
|
RepoID: build.RepoID,
|
|
Number: build.Number,
|
|
Status: core.StatusFailing,
|
|
Version: build.Version,
|
|
}
|
|
err := store.Update(noContext, before)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if got, want := before.Version, build.Version+1; got != want {
|
|
t.Errorf("Want incremented version %d, got %d", want, got)
|
|
}
|
|
after, err := store.Find(noContext, before.ID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if got, want := after.Version, build.Version+1; got != want {
|
|
t.Errorf("Want incremented version %d, got %d", want, got)
|
|
}
|
|
if got, want := after.Status, before.Status; got != want {
|
|
t.Errorf("Want updated build status %v, got %v", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildLocking(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
item, err := store.Find(noContext, build.ID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
item.Version = 1
|
|
err = store.Update(noContext, item)
|
|
if err == nil {
|
|
t.Errorf("Want Optimistic Lock Error, got nil")
|
|
} else if err != db.ErrOptimisticLock {
|
|
t.Errorf("Want Optimistic Lock Error")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildDelete(store *buildStore, build *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
item, err := store.Find(noContext, build.ID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = store.Delete(noContext, item)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = store.Find(noContext, item.ID)
|
|
if want, got := sql.ErrNoRows, err; got != want {
|
|
t.Errorf("Want %q, got %q", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildPurge(store *buildStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
store.db.Update(func(execer db.Execer, binder db.Binder) error {
|
|
_, err := execer.Exec("DELETE FROM builds")
|
|
return err
|
|
})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 98}, nil)
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 99}, nil)
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 100}, nil)
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 101}, nil)
|
|
|
|
before, err := store.List(noContext, 1, 100, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if got, want := len(before), 4; got != want {
|
|
t.Errorf("Want build count %d, got %d", want, got)
|
|
}
|
|
err = store.Purge(noContext, 1, 100)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
after, err := store.List(noContext, 1, 100, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if got, want := len(after), 2; got != want {
|
|
t.Errorf("Want build count %d, got %d", want, got)
|
|
}
|
|
for _, build := range after {
|
|
if build.Number < 100 {
|
|
t.Errorf("Expect purge if build number is less than 100")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildCount(store *buildStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
store.db.Update(func(execer db.Execer, binder db.Binder) error {
|
|
_, err := execer.Exec("DELETE FROM builds")
|
|
return err
|
|
})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 98}, nil)
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 99}, nil)
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 100}, nil)
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 101}, nil)
|
|
|
|
count, err := store.Count(noContext)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if got, want := count, int64(4); got != want {
|
|
t.Errorf("Want build count %d, got %d", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildPending(store *buildStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
store.db.Update(func(execer db.Execer, binder db.Binder) error {
|
|
execer.Exec("DELETE FROM builds")
|
|
execer.Exec("DELETE FROM stages")
|
|
return nil
|
|
})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 98, Status: core.StatusPending}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusPending}})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 99, Status: core.StatusPending}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusPending}})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 100, Status: core.StatusRunning}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusRunning}})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 101, Status: core.StatusPassing}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusPassing}})
|
|
|
|
count, err := store.Count(noContext)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if got, want := count, int64(4); got != want {
|
|
t.Errorf("Want build count %d, got %d", want, got)
|
|
}
|
|
list, err := store.Pending(noContext)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if got, want := len(list), 2; got != want {
|
|
t.Errorf("Want list count %d, got %d", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildRunning(store *buildStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
store.db.Update(func(execer db.Execer, binder db.Binder) error {
|
|
execer.Exec("DELETE FROM builds")
|
|
execer.Exec("DELETE FROM stages")
|
|
return nil
|
|
})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 98, Status: core.StatusRunning}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusRunning}})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 99, Status: core.StatusRunning}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusRunning}})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 100, Status: core.StatusBlocked}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusBlocked}})
|
|
store.Create(noContext, &core.Build{RepoID: 1, Number: 101, Status: core.StatusPassing}, []*core.Stage{&core.Stage{RepoID: 1, Number: 1, Status: core.StatusPassing}})
|
|
|
|
count, err := store.Count(noContext)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if got, want := count, int64(4); got != want {
|
|
t.Errorf("Want build count %d, got %d", want, got)
|
|
}
|
|
list, err := store.Running(noContext)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if got, want := len(list), 2; got != want {
|
|
t.Errorf("Want list count %d, got %d", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildLatest(store *buildStore) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
store.db.Update(func(execer db.Execer, binder db.Binder) error {
|
|
execer.Exec("DELETE FROM stages")
|
|
execer.Exec("DELETE FROM latest")
|
|
execer.Exec("DELETE FROM builds")
|
|
return nil
|
|
})
|
|
|
|
//
|
|
// step 1: insert the initial builds
|
|
//
|
|
|
|
build := &core.Build{
|
|
RepoID: 1,
|
|
Number: 99,
|
|
Event: core.EventPush,
|
|
Ref: "refs/heads/master",
|
|
Target: "master",
|
|
}
|
|
|
|
err := store.Create(noContext, build, []*core.Stage{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
develop := &core.Build{
|
|
RepoID: 1,
|
|
Number: 100,
|
|
Event: core.EventPush,
|
|
Ref: "refs/heads/develop",
|
|
Target: "develop",
|
|
}
|
|
err = store.Create(noContext, develop, []*core.Stage{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
err = store.Create(noContext, &core.Build{
|
|
RepoID: 1,
|
|
Number: 999,
|
|
Event: core.EventPullRequest,
|
|
Ref: "refs/pulls/10/head",
|
|
Source: "develop",
|
|
Target: "master",
|
|
}, []*core.Stage{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
//
|
|
// step 2: verify the latest build number was captured
|
|
//
|
|
|
|
latest, _ := store.LatestBranches(noContext, build.RepoID)
|
|
if len(latest) != 2 {
|
|
t.Errorf("Expect latest branch list == 1, got %d", len(latest))
|
|
return
|
|
}
|
|
if got, want := latest[0].Number, build.Number; got != want {
|
|
t.Errorf("Expected latest master build number %d, got %d", want, got)
|
|
}
|
|
if got, want := latest[1].Number, develop.Number; got != want {
|
|
t.Errorf("Expected latest develop build number %d, got %d", want, got)
|
|
return
|
|
}
|
|
|
|
build = &core.Build{
|
|
RepoID: 1,
|
|
Number: 101,
|
|
Event: core.EventPush,
|
|
Ref: "refs/heads/master",
|
|
Target: "master",
|
|
}
|
|
err = store.Create(noContext, build, []*core.Stage{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
latest, _ = store.LatestBranches(noContext, build.RepoID)
|
|
if len(latest) != 2 {
|
|
t.Errorf("Expect latest branch list == 1")
|
|
return
|
|
}
|
|
if got, want := latest[1].Number, build.Number; got != want {
|
|
t.Errorf("Expected latest build number %d, got %d", want, got)
|
|
return
|
|
}
|
|
|
|
err = store.DeleteBranch(noContext, build.RepoID, build.Target)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
|
|
latest, _ = store.LatestBranches(noContext, build.RepoID)
|
|
if len(latest) != 1 {
|
|
t.Errorf("Expect latest branch list == 1 after delete")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuild(item *core.Build) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
if got, want := item.RepoID, int64(1); got != want {
|
|
t.Errorf("Want build repo ID %d, got %d", want, got)
|
|
}
|
|
if got, want := item.Number, int64(99); got != want {
|
|
t.Errorf("Want build number %d, got %d", want, got)
|
|
}
|
|
if got, want := item.Ref, "refs/heads/master"; got != want {
|
|
t.Errorf("Want build ref %q, got %q", want, got)
|
|
}
|
|
}
|
|
}
|