Merged in feature/testing (pull request #102)

Minimum Testing Threshold

* mintests
This commit is contained in:
Michael McGuinness
2025-03-12 12:36:44 +00:00
parent d60eb9b16b
commit 65c0df50e6
9 changed files with 197 additions and 43 deletions
+1 -1
View File
@@ -10,4 +10,4 @@ includes:
vars:
IMAGE_NAME: queryorchestration
COVERAGE_THRESHOLD: 80
FUNCTION_COVERAGE_THRESHOLD: 10
FUNCTION_COVERAGE_THRESHOLD: 60
+10 -21
View File
@@ -5,7 +5,6 @@ import (
"errors"
"log/slog"
"net"
"net/http"
"strconv"
"time"
@@ -17,7 +16,6 @@ import (
"github.com/labstack/echo/v4/middleware"
_ "github.com/lib/pq"
echoSwagger "github.com/swaggo/echo-swagger"
"gopkg.in/yaml.v3"
)
type Config interface {
@@ -90,7 +88,6 @@ func getSlogCustomEchoMiddleware(logger *slog.Logger) echo.MiddlewareFunc {
}
func New(ctx context.Context, cfg Config) (*Server, error) {
cleanup, err := server.New(ctx, cfg)
if err != nil {
return nil, err
@@ -114,25 +111,17 @@ func New(ctx context.Context, cfg Config) (*Server, error) {
return nil, err
}
e.GET("/swagger/doc.json", func(c echo.Context) error {
spec, err := opnapi.MarshalJSON()
if err != nil {
return err
}
return c.Blob(http.StatusOK, "application/json", spec)
})
e.GET("/swagger/doc.yaml", func(c echo.Context) error {
spec, err := opnapi.MarshalYAML()
if err != nil {
return err
}
yaml, err := yaml.Marshal(spec)
if err != nil {
return err
}
jsonFunc, err := getSwaggerJSONFunc(opnapi)
if err != nil {
return nil, err
}
e.GET("/swagger/doc.json", jsonFunc)
return c.Blob(http.StatusOK, "application/yaml", yaml)
})
yamlFunc, err := getSwaggerYAMLFunc(opnapi)
if err != nil {
return nil, err
}
e.GET("/swagger/doc.yaml", yamlFunc)
e.GET("/swagger/*", echoSwagger.EchoWrapHandler(
echoSwagger.DocExpansion("full"),
+34
View File
@@ -2,16 +2,22 @@ package service
import (
"context"
"log/slog"
"net/http"
"net/http/httptest"
"os"
"path"
"strings"
"testing"
"queryorchestration/internal/serviceconfig/logger"
"queryorchestration/internal/test"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNew(t *testing.T) {
@@ -78,3 +84,31 @@ func TestGetRouter(t *testing.T) {
assert.Equal(t, &echo.Echo{}, r)
assert.Equal(t, r, c.Router)
}
func TestGetSlogCustomEchoMiddleware(t *testing.T) {
l := &logger.TestLogger{
T: t,
}
sl := slog.New(l)
handlerFunc := getSlogCustomEchoMiddleware(sl)
require.NotNil(t, handlerFunc)
mid := func(c echo.Context) error {
sl.Info("in middleware", "location", "middleware")
return nil
}
myFunc := handlerFunc(mid)
require.NotNil(t, myFunc)
uri := "/example"
req := httptest.NewRequest(http.MethodPost, uri, strings.NewReader("hello"))
rec := httptest.NewRecorder()
ctx := echo.New().NewContext(req, rec)
err := myFunc(ctx)
require.Nil(t, err)
assert.Len(t, l.Logs, 2)
assert.Equal(t, "middleware", l.Logs[0]["location"])
assert.Equal(t, uri, l.Logs[1]["uri"])
}
+35
View File
@@ -0,0 +1,35 @@
package service
import (
"net/http"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"gopkg.in/yaml.v3"
)
func getSwaggerJSONFunc(opnapi *openapi3.T) (func(echo.Context) error, error) {
spec, err := opnapi.MarshalJSON()
if err != nil {
return nil, err
}
return func(c echo.Context) error {
return c.Blob(http.StatusOK, "application/json", spec)
}, nil
}
func getSwaggerYAMLFunc(opnapi *openapi3.T) (func(echo.Context) error, error) {
spec, err := opnapi.MarshalYAML()
if err != nil {
return nil, err
}
yaml, err := yaml.Marshal(spec)
if err != nil {
return nil, err
}
return func(c echo.Context) error {
return c.Blob(http.StatusOK, "application/yaml", yaml)
}, nil
}
+47
View File
@@ -0,0 +1,47 @@
package service
import (
"net/http"
"net/http/httptest"
queryservice "queryorchestration/api/queryService"
"strings"
"testing"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetSwaggerJSONFunc(t *testing.T) {
openapi, err := queryservice.GetSwagger()
require.NoError(t, err)
f, err := getSwaggerJSONFunc(openapi)
require.NoError(t, err)
require.NotNil(t, f)
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("hello"))
rec := httptest.NewRecorder()
ctx := echo.New().NewContext(req, rec)
err = f(ctx)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Result().StatusCode)
}
func TestGetSwaggerYAMLFunc(t *testing.T) {
openapi, err := queryservice.GetSwagger()
require.NoError(t, err)
f, err := getSwaggerYAMLFunc(openapi)
require.NoError(t, err)
require.NotNil(t, f)
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("hello"))
rec := httptest.NewRecorder()
ctx := echo.New().NewContext(req, rec)
err = f(ctx)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, rec.Result().StatusCode)
}
+12 -8
View File
@@ -25,10 +25,16 @@ var startupTime time.Time
var startupTimeOnce sync.Once
func GetVersionTimestamp() time.Time {
startupTimeOnce.Do(func() {
info, ok := debug.ReadBuildInfo()
startupTimeOnce.Do(getStartTime(&startupTime, debug.ReadBuildInfo))
return startupTime
}
func getStartTime(startupTime *time.Time, readBuildInfo func() (info *debug.BuildInfo, ok bool)) func() {
return func() {
info, ok := readBuildInfo()
if !ok {
startupTime = time.Now()
*startupTime = time.Now()
return
}
@@ -38,7 +44,7 @@ func GetVersionTimestamp() time.Time {
// Parse the build timestamp
buildTime, err := time.Parse(time.RFC3339, setting.Value)
if err == nil {
startupTime = buildTime
*startupTime = buildTime
return
}
break
@@ -46,10 +52,8 @@ func GetVersionTimestamp() time.Time {
}
// Return current time if no build time found
startupTime = time.Now()
})
return startupTime
*startupTime = time.Now()
}
}
func GetVersionUnixTimestamp() int64 {
+49 -13
View File
@@ -1,46 +1,45 @@
package build_test
package build
import (
"runtime/debug"
"testing"
"time"
"queryorchestration/internal/serviceconfig/build"
"github.com/stretchr/testify/assert"
)
func TestGetVersionUnixTimestamp(t *testing.T) {
t1 := build.GetVersionUnixTimestamp()
t1 := GetVersionUnixTimestamp()
assert.NotZero(t, t1)
time.Sleep(time.Millisecond * 100)
t2 := build.GetVersionUnixTimestamp()
t2 := GetVersionUnixTimestamp()
assert.Equal(t, t1, t2)
}
func TestIsValidUnixVersion(t *testing.T) {
assert.NotNil(t, build.IsValidUnixVersion(0))
assert.NotNil(t, build.IsValidUnixVersion(time.Now().Add(time.Second).UnixMilli()))
assert.Nil(t, build.IsValidUnixVersion(1))
assert.NotNil(t, IsValidUnixVersion(0))
assert.NotNil(t, IsValidUnixVersion(time.Now().Add(time.Second).UnixMilli()))
assert.Nil(t, IsValidUnixVersion(1))
}
func TestGetVersionTimestamp(t *testing.T) {
// Test 1: First call should set the timestamp
t1 := build.GetVersionTimestamp()
t1 := GetVersionTimestamp()
if t1.IsZero() {
t.Error("GetVersionTimestamp returned zero time")
}
// Test 2: Second call should return exactly the same time
time.Sleep(time.Millisecond * 100) // Small delay to ensure time would be different if not cached
t2 := build.GetVersionTimestamp()
t2 := GetVersionTimestamp()
if !t1.Equal(t2) {
t.Errorf("Timestamps should be identical but got t1=%v, t2=%v", t1, t2)
}
// Test 3: Even after a longer delay, should still return the same time
time.Sleep(time.Second) // Longer delay
t3 := build.GetVersionTimestamp()
t3 := GetVersionTimestamp()
if !t1.Equal(t3) {
t.Errorf("Timestamp changed after delay: original=%v, new=%v", t1, t3)
}
@@ -51,9 +50,46 @@ func TestGetVersionTimestamp(t *testing.T) {
}
}
func TestGetStartTime(t *testing.T) {
t.Run("vcs time", func(t *testing.T) {
var tt time.Time
expectedTime := time.Now()
f := getStartTime(&tt, func() (info *debug.BuildInfo, ok bool) {
return &debug.BuildInfo{
Settings: []debug.BuildSetting{
{
Key: "vcs.time",
Value: expectedTime.Format(time.RFC3339),
},
},
}, true
})
assert.NotNil(t, f)
f()
assert.Equal(t, expectedTime.UTC().Truncate(time.Second), tt)
})
t.Run("vcs time - invalid format", func(t *testing.T) {
var tt time.Time
expectedTime := time.Now()
f := getStartTime(&tt, func() (info *debug.BuildInfo, ok bool) {
return &debug.BuildInfo{
Settings: []debug.BuildSetting{
{
Key: "vcs.time",
Value: "invalid",
},
},
}, true
})
assert.NotNil(t, f)
f()
assert.True(t, expectedTime.Before(tt))
})
}
func TestGetVersion(t *testing.T) {
// Test 1: Basic call
version := build.GetVersion()
version := GetVersion()
if version == "" {
t.Error("Version should not be empty")
}
@@ -67,7 +103,7 @@ func TestGetVersion(t *testing.T) {
}
// Test 3: Multiple calls should be consistent
version2 := build.GetVersion()
version2 := GetVersion()
if version != version2 {
t.Errorf("Version not consistent between calls: '%s' != '%s'", version, version2)
}
+7
View File
@@ -6,6 +6,7 @@ import (
"queryorchestration/internal/serviceconfig"
"github.com/docker/go-connections/nat"
"github.com/stretchr/testify/assert"
)
@@ -31,6 +32,12 @@ func TestCreateContainer(t *testing.T) {
Name: QueryService,
Cfg: cfg,
Network: ncfg,
Env: map[string]string{
"EXAMPLE": "value",
},
ExposedPorts: []nat.Port{
nat.Port("8080/tcp"),
},
}
container, cleanup := createContainer(t, ctx, ccfg)
+2
View File
@@ -60,6 +60,8 @@ paths:
- ClientService
summary: Get a client by ID
description: Retrieves a specific client by its ID.
security:
- placeholderAuth: []
responses:
"200":
description: Client details.