Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions cmd/smoke-buildinfo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ package main

import (
"fmt"
"io"
"os"

"instant.dev/common/buildinfo"
)

func main() {
fmt.Printf("GitSHA=%s BuildTime=%s Version=%s\n",
// render writes the buildinfo smoke line to w. Extracted from main() so the
// output shape is unit-testable without spawning the binary.
func render(w io.Writer) {
fmt.Fprintf(w, "GitSHA=%s BuildTime=%s Version=%s\n",
buildinfo.GitSHA, buildinfo.BuildTime, buildinfo.Version)
}

func main() {
render(os.Stdout)
}
34 changes: 34 additions & 0 deletions cmd/smoke-buildinfo/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"bytes"
"strings"
"testing"

"instant.dev/common/buildinfo"
)

// TestRender pins the smoke-buildinfo output shape: a single line carrying
// the three linked-in buildinfo fields. The format is what `make
// smoke-buildinfo` greps to confirm the -ldflags -X override landed.
func TestRender(t *testing.T) {
var buf bytes.Buffer
render(&buf)

out := buf.String()
if !strings.HasPrefix(out, "GitSHA=") {
t.Fatalf("output must start with GitSHA=; got %q", out)
}
if !strings.HasSuffix(out, "\n") {
t.Errorf("output must end with newline; got %q", out)
}
for _, want := range []string{
"GitSHA=" + buildinfo.GitSHA,
"BuildTime=" + buildinfo.BuildTime,
"Version=" + buildinfo.Version,
} {
if !strings.Contains(out, want) {
t.Errorf("output %q missing %q", out, want)
}
}
}
25 changes: 25 additions & 0 deletions internal/logsafe/logsafe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,31 @@ func TestToken_BasicShapes(t *testing.T) {
}
}

// TestItoa covers the internal base-10 itoa helper directly, including
// the n==0 and (defensive) n<0 branches that Token() can never reach via
// a real len() argument. Pinning these keeps the helper safe to reuse.
func TestItoa(t *testing.T) {
cases := []struct {
in int
want string
}{
{0, "0"},
{1, "1"},
{7, "7"},
{42, "42"},
{1000, "1000"},
// Defensive negative path — len() can't produce this, but the
// helper must not crash and must render a leading minus sign.
{-1, "-1"},
{-42, "-42"},
}
for _, c := range cases {
if got := itoa(c.in); got != c.want {
t.Errorf("itoa(%d) = %q; want %q", c.in, got, c.want)
}
}
}

// TestToken_NoLeakBeyondPrefix is the substantive regression guard:
// for any token longer than 8 chars, the redacted output must NOT
// contain any character from position [8:] of the original. Catches
Expand Down
59 changes: 59 additions & 0 deletions internal/migrations/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,65 @@ func TestReader_NilDB(t *testing.T) {
}
}

// TestNewReader_Defaults exercises both fallback branches: ttl <= 0 must
// clamp to defaultTTL, and a nil clock must default to time.Now. We can't
// read the unexported fields from outside, so we verify behaviourally:
// with the defaulted clock + TTL, a fresh Get refreshes from the DB and a
// second immediate Get serves from cache (proving the TTL is the positive
// defaultTTL, not the passed-in 0).
func TestNewReader_Defaults(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New: %v", err)
}
defer db.Close()

// Exactly one query pair — the second Get must hit the cache, which
// only happens if ttl was clamped to a positive defaultTTL (not 0).
mock.ExpectQuery(`SELECT filename FROM schema_migrations`).
WillReturnRows(sqlmock.NewRows([]string{"filename"}).AddRow("001_initial.sql"))
mock.ExpectQuery(`SELECT COUNT\(\*\)`).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))

// ttl=0 -> defaultTTL; clock=nil -> time.Now.
r := NewReader(db, 0, nil)
a := r.Get(context.Background())
b := r.Get(context.Background())
if a != b || a.Status != StatusOK || a.Count != 1 {
t.Fatalf("expected cached StatusOK after defaulting: %+v vs %+v", a, b)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet: %v", err)
}
}

// TestQueryState_CountError covers the COUNT query failure path: the
// filename query succeeds but the count query errors, so queryState must
// return StatusUnknown + the error.
func TestQueryState_CountError(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New: %v", err)
}
defer db.Close()

mock.ExpectQuery(`SELECT filename FROM schema_migrations`).
WillReturnRows(sqlmock.NewRows([]string{"filename"}).AddRow("042_x.sql"))
mock.ExpectQuery(`SELECT COUNT\(\*\)`).
WillReturnError(errors.New("count query failed"))

s, err := queryState(context.Background(), db)
if err == nil {
t.Fatalf("expected error from count query")
}
if s.Status != StatusUnknown {
t.Fatalf("Status: got %q want %q", s.Status, StatusUnknown)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet: %v", err)
}
}

// TestQueryState_NoRows surfaces StatusOK with empty filename. A fresh DB
// where schema_migrations exists but is empty (boot-time race) is valid.
func TestQueryState_NoRows(t *testing.T) {
Expand Down
Loading
Loading