pelican/internal/db/database_test.go
Dan Anglin 5189ebe7bb
All checks were successful
/ test (pull_request) Successful in 40s
/ lint (pull_request) Successful in 42s
refactor: remove duplicate write function in db
Remove the original 'Write' function from the db package and rename the
'WriteMany' function to 'Write' as it can already write one or many Bolt
items to the database.

Also update the test suites and add more coverage in the board package.
2024-01-23 18:31:01 +00:00

375 lines
8.3 KiB
Go

package db_test
import (
"bytes"
"encoding/gob"
"os"
"path/filepath"
"reflect"
"testing"
"codeflow.dananglin.me.uk/apollo/pelican/internal/board"
"codeflow.dananglin.me.uk/apollo/pelican/internal/db"
bolt "go.etcd.io/bbolt"
)
func TestWriteAndReadStatusList(t *testing.T) {
t.Parallel()
var database *bolt.DB
var err error
projectDir, err := projectRoot()
if err != nil {
t.Fatalf(err.Error())
}
testDB := filepath.Join(projectDir, "test", "databases", "Database_TestWriteAndReadStatusList.db")
os.Remove(testDB)
if database, err = db.OpenDatabase(testDB); err != nil {
t.Fatalf("An error occurred whilst opening the test database %s, %s.", testDB, err)
}
defer func() {
_ = database.Close()
}()
testCreateStatusList(t, database)
testReadStatusList(t, database)
}
func testCreateStatusList(t *testing.T, database *bolt.DB) {
t.Helper()
newStatusList := []board.Status{
{
ID: -1,
Name: "Backlog",
CardIds: []int{1, 14, 9, 10},
Position: 1,
},
{
ID: -1,
Name: "Next",
CardIds: []int{2, 5, 12},
Position: 2,
},
{
ID: -1,
Name: "In progress",
CardIds: []int{3, 14},
Position: 3,
},
{
ID: -1,
Name: "Finished!",
CardIds: []int{4, 6, 7, 8, 11, 13},
Position: 4,
},
}
boltItems := make([]db.BoltItem, len(newStatusList))
for i := range newStatusList {
boltItems[i] = &newStatusList[i]
}
if _, err := db.Write(database, db.WriteModeCreate, db.StatusBucket, boltItems); err != nil {
t.Fatalf("An error occurred whilst writing the initial status list to the database, %s", err)
}
}
func testReadStatusList(t *testing.T, database *bolt.DB) {
t.Helper()
data, err := db.ReadAll(database, db.StatusBucket)
if err != nil {
t.Fatalf("An error occurred whilst reading the modified status list from the database, %s", err)
}
got := make([]board.Status, len(data))
for ind, d := range data {
buf := bytes.NewBuffer(d)
decoder := gob.NewDecoder(buf)
var status board.Status
if err := decoder.Decode(&status); err != nil {
t.Fatalf("An error occurred whilst decoding data, %s", err)
}
got[ind] = status
}
want := []board.Status{
{
ID: 1,
Name: "Backlog",
CardIds: []int{1, 14, 9, 10},
Position: 1,
},
{
ID: 2,
Name: "Next",
CardIds: []int{2, 5, 12},
Position: 2,
},
{
ID: 3,
Name: "In progress",
CardIds: []int{3, 14},
Position: 3,
},
{
ID: 4,
Name: "Finished!",
CardIds: []int{4, 6, 7, 8, 11, 13},
Position: 4,
},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Unexpected status list read from the database: got %+v, want %+v", got, want)
} else {
t.Logf("Expected status list read from the database: got %+v", got)
}
}
func TestReadAndWriteCards(t *testing.T) {
t.Parallel()
var database *bolt.DB
var err error
projectDir, err := projectRoot()
if err != nil {
t.Fatalf(err.Error())
}
testDB := filepath.Join(projectDir, "test", "databases", "Database_TestReadWriteCard.db")
os.Remove(testDB)
if database, err = db.OpenDatabase(testDB); err != nil {
t.Fatalf("An error occurred whilst opening the test database %s, %s.", testDB, err)
}
defer func() {
_ = database.Close()
}()
singleCard := board.Card{
ID: -1,
Title: "A test task.",
Description: "This task should be completed.",
}
singleCardID := testCreateOneCard(t, database, singleCard)
testReadOneCard(t, database, singleCardID)
manyCards := []board.Card{
{
ID: -1,
Title: "Test card A.",
Description: "This is test card A.",
},
{
ID: -1,
Title: "Test card B.",
Description: "This is test card B.",
},
{
ID: -1,
Title: "Test card C.",
Description: "This is test card C.",
},
}
manyCardIDs := testCreateManyCard(t, database, manyCards)
testReadManyCards(t, database, manyCardIDs)
}
func testCreateOneCard(t *testing.T, database *bolt.DB, card board.Card) int {
t.Helper()
cardIDs, err := db.Write(database, db.WriteModeCreate, db.CardBucket, []db.BoltItem{&card})
if err != nil {
t.Fatalf("An error occurred whilst writing the card to the database, %s", err)
}
if len(cardIDs) != 1 {
t.Fatalf("Unexpected number of card IDs returned from db.Write(); want: 1; got %d", len(cardIDs))
}
return cardIDs[0]
}
func testReadOneCard(t *testing.T, database *bolt.DB, cardID int) {
t.Helper()
data, err := db.Read(database, db.CardBucket, cardID)
if err != nil {
t.Fatalf("An error occurred whilst loading the modified from the database, %s", err)
}
var got board.Card
buf := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buf)
if err := decoder.Decode(&got); err != nil {
t.Fatalf("Unable to decode data, %s", err)
}
want := board.Card{
ID: 1,
Title: "A test task.",
Description: "This task should be completed.",
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Unexpected card read from the database: got %+v, want %+v", got, want)
} else {
t.Logf("Expected card read from the database: got %+v", got)
}
}
func testCreateManyCard(t *testing.T, database *bolt.DB, cards []board.Card) []int {
t.Helper()
boltItems := make([]db.BoltItem, len(cards))
for i := range cards {
boltItems[i] = &cards[i]
}
ids, err := db.Write(database, db.WriteModeCreate, db.CardBucket, boltItems)
if err != nil {
t.Fatalf("An error occurred whilst writing many cards to the database, %s", err)
}
return ids
}
func testReadManyCards(t *testing.T, database *bolt.DB, cardIDs []int) {
t.Helper()
data, err := db.ReadMany(database, db.CardBucket, cardIDs)
if err != nil {
t.Fatalf("An error occurred whilst reading the data from the database, %s", err)
}
got := make([]board.Card, len(data))
for i, d := range data {
buf := bytes.NewBuffer(d)
decoder := gob.NewDecoder(buf)
var c board.Card
if err := decoder.Decode(&c); err != nil {
t.Fatalf("An error occurred whilst decoding data, %s", err)
}
got[i] = c
}
want := []board.Card{
{
ID: 2,
Title: "Test card A.",
Description: "This is test card A.",
},
{
ID: 3,
Title: "Test card B.",
Description: "This is test card B.",
},
{
ID: 4,
Title: "Test card C.",
Description: "This is test card C.",
},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Unexpected list of cards read from the database: got %+v, want %+v", got, want)
} else {
t.Logf("Expected list of cards read from the database: got %+v", got)
}
}
func TestDeleteOneCard(t *testing.T) {
t.Parallel()
var database *bolt.DB
var err error
projectDir, err := projectRoot()
if err != nil {
t.Fatalf(err.Error())
}
testDB := filepath.Join(projectDir, "test", "databases", "Database_TestDeleteOneCard.db")
os.Remove(testDB)
if database, err = db.OpenDatabase(testDB); err != nil {
t.Fatalf("An error occurred whilst opening the test database %s, %s.", testDB, err)
}
defer func() {
_ = database.Close()
}()
// Create one card, get card ID.
card := board.Card{
ID: -1,
Title: "Test card",
Description: "",
}
cardIDs, err := db.Write(database, db.WriteModeCreate, db.CardBucket, []db.BoltItem{&card})
if err != nil {
t.Fatalf("ERROR: Unable to create the card in the database, %v", err)
}
if len(cardIDs) != 1 {
t.Fatalf("Unexpected number of card IDs returned from db.Write(); want: 1; got %d", len(cardIDs))
}
cardID := cardIDs[0]
cards, err := db.ReadAll(database, db.CardBucket)
if err != nil {
t.Fatalf("ERROR: Unable to read the cards from the database, %v", err)
}
numCards := len(cards)
if numCards != 1 {
t.Fatalf("ERROR: Unexpected number of cards returned from the card bucket; want 1; got %d", numCards)
}
if err := db.Delete(database, db.CardBucket, cardID); err != nil {
t.Fatalf("ERROR: Unable to delete the card from the database, %v", err)
}
// Get all cards, expect length = 0; error if not 0
cards, err = db.ReadAll(database, db.CardBucket)
if err != nil {
t.Fatalf("ERROR: Unable to read the cards from the database, %v", err)
}
numCards = len(cards)
if numCards != 0 {
t.Errorf("%s\tUnexpected number of cards returned from the card bucket; want 0; got %d", failure, numCards)
} else {
t.Logf("%s\tThe card was successfully deleted from the database.", success)
}
}