From fd369c70eccbd9dd2a86f7fa7a03a5ba52cf4b9a Mon Sep 17 00:00:00 2001 From: Markus Opolka Date: Fri, 23 Aug 2024 15:34:39 +0200 Subject: [PATCH] Add basic unittests --- cleanup.go | 6 --- go.mod | 1 + go.sum | 3 ++ main.go | 5 +- main_test.go | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 main_test.go diff --git a/cleanup.go b/cleanup.go index bf4a023..de8153a 100644 --- a/cleanup.go +++ b/cleanup.go @@ -40,8 +40,6 @@ func (t Table) OldestTime(db *sql.DB, instanceID int) (ts time.Time, err error) query := fmt.Sprintf("SELECT %s FROM %s%s WHERE instance_id = ? ORDER BY %s ASC LIMIT 1", //nolint:gosec t.TimeColumn, IcingaPrefix, t.Name, t.TimeColumn) - // log.Debugf("running query: %s - [%d]", query, instanceID) - row := db.QueryRow(query, instanceID) var tsString string @@ -72,8 +70,6 @@ func (t Table) Cleanup(db *sql.DB, instanceID int, since time.Time, limit int) ( query := fmt.Sprintf("DELETE FROM %s%s WHERE instance_id = ? AND %s < ? LIMIT %d", //nolint:gosec IcingaPrefix, t.Name, t.TimeColumn, limit) - // log.Debugf("running query: %s - [%d %s]", query, instanceID, since) - result, err := db.Exec(query, instanceID, since) if err != nil { err = fmt.Errorf("could not purge rows for %s: %w", t.Name, err) @@ -88,8 +84,6 @@ func (t Table) Count(db *sql.DB, instanceID int, since time.Time) (rows int64, e query := fmt.Sprintf("SELECT count(*) FROM %s%s WHERE instance_id = ? AND %s < ?", //nolint:gosec IcingaPrefix, t.Name, t.TimeColumn) - // log.Debugf("running query: %s - [%d %s]", query, instanceID, since) - row := db.QueryRow(query, instanceID, since) err = row.Scan(&rows) diff --git a/go.mod b/go.mod index 87f81af..d9f91d5 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/NETWAYS/ido-cleanup go 1.21 require ( + github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/go-sql-driver/mysql v1.8.1 github.com/spf13/pflag v1.0.5 ) diff --git a/go.sum b/go.sum index 14ab1d3..46813b1 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,9 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= diff --git a/main.go b/main.go index 80a0e11..77c317a 100644 --- a/main.go +++ b/main.go @@ -75,7 +75,7 @@ func main() { db.SetConnMaxLifetime(time.Minute * 15) // Load instance ID - instanceID, err := getInstanceID(db) + instanceID, err := getInstanceID(db, instance) if err != nil { _ = db.Close() @@ -161,6 +161,7 @@ func handleArguments() { pflag.PrintDefaults() } + // knownTables is a slice of Table structs for _, table := range knownTables { age := uint(0) if v, ok := defaultAges[table.Name]; ok { @@ -249,7 +250,7 @@ func runCleanup(db *sql.DB, instanceID int, logger *slog.Logger) (busy bool) { return } -func getInstanceID(db *sql.DB) (id int, err error) { +func getInstanceID(db *sql.DB, instance string) (id int, err error) { row := db.QueryRow("SELECT instance_id FROM icinga_instances WHERE instance_name = ?", instance) err = row.Scan(&id) diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..3c01109 --- /dev/null +++ b/main_test.go @@ -0,0 +1,147 @@ +package main + +import ( + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestGetInstanceID_WithOK(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + expected := 1 + + rows := sqlmock.NewRows([]string{"instance_id"}). + AddRow(expected) + + mock.ExpectQuery("SELECT instance_id FROM icinga_instances WHERE instance_name = ?").WillReturnRows(rows) + + id, err := getInstanceID(db, "default") + + if err != nil { + t.Errorf("error was not expected while getting instance: %s", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } + + if id != expected { + t.Errorf("actual: %d, expected: %d", id, expected) + } +} + +func TestGetInstanceID_WithError(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + _, DbErr := getInstanceID(db, "default") + + if err != nil { + t.Errorf("error was not expected while getting instance: %s", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } + + if DbErr == nil { + t.Errorf("expected an error got nil") + } +} + +func TestOldestTime_WithOK(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + expected := "2024-07-02 08:25:44" + rows := sqlmock.NewRows([]string{"start_time"}). + AddRow(expected) + + mock.ExpectQuery("SELECT start_time FROM icinga_notifications WHERE (.+) ORDER BY start_time ASC LIMIT 1").WillReturnRows(rows) + + table := Table{"notifications", "start_time"} + oldest, err := table.OldestTime(db, 1) + + if "2024-07-02 08:25:44 +0000 UTC" != oldest.String() { + t.Errorf("returned timestamp not expected: %s", oldest.String()) + } + + if err != nil { + t.Errorf("error was not expected while getting oldest time: %s", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestCleanup_WithOK(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + ts := time.Now() + mock.ExpectExec("DELETE FROM icinga_notifications WHERE (.+) AND start_time (.+) LIMIT 10"). + WithArgs(1, ts). + WillReturnResult(sqlmock.NewResult(1, 1)) + + table := Table{"notifications", "start_time"} + r, err := table.Cleanup(db, 1, ts, 10) + + if 1 != r { + t.Errorf("returned rows not expected: %d", r) + } + + if err != nil { + t.Errorf("error was not expected while cleanup: %s", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestCount_WithOK(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + rows := sqlmock.NewRows([]string{"count(*)"}). + AddRow(123) + + ts := time.Now() + mock.ExpectQuery("SELECT count(.+) FROM icinga_notifications WHERE instance_id = (.+) AND start_time < (.+)"). + WithArgs(1, ts). + WillReturnRows(rows) + + table := Table{"notifications", "start_time"} + r, err := table.Count(db, 1, ts) + + if 123 != r { + t.Errorf("returned rows not expected: %d", r) + } + + if err != nil { + t.Errorf("error was not expected while cleanup: %s", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +}