updates Go dependencies, refactors and expands unit tests for config, logging, OpenTelemetry, HTTP, and gRPC components
This commit is contained in:
@@ -1,123 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/config"
|
||||
)
|
||||
|
||||
func TestMustSetupConfigAndLogging(t *testing.T) {
|
||||
// Configure app and logger
|
||||
type inputs struct {
|
||||
envs map[string]string
|
||||
}
|
||||
type outputs struct {
|
||||
appName string
|
||||
logLevel zerolog.Level
|
||||
logRegexChecks []*regexp.Regexp
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
inputs inputs
|
||||
want outputs
|
||||
}{
|
||||
{
|
||||
name: "Test json logging with short timestamp",
|
||||
inputs: inputs{
|
||||
envs: map[string]string{
|
||||
"APP_NAME": "testapp",
|
||||
"APP_LOG_LEVEL": "warn",
|
||||
"APP_LOG_FORMAT": "json",
|
||||
"APP_LOG_TIME_FORMAT": "short",
|
||||
},
|
||||
},
|
||||
want: outputs{
|
||||
appName: "testapp",
|
||||
logLevel: zerolog.WarnLevel,
|
||||
logRegexChecks: []*regexp.Regexp{
|
||||
regexp.MustCompile(`^\{.*time":"\d{1,}:\d{2}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test json logging with unix timestamp",
|
||||
inputs: inputs{
|
||||
envs: map[string]string{
|
||||
"APP_NAME": "testapp",
|
||||
"APP_LOG_LEVEL": "info",
|
||||
"APP_LOG_FORMAT": "json",
|
||||
"APP_LOG_TIME_FORMAT": "unix",
|
||||
},
|
||||
},
|
||||
want: outputs{
|
||||
appName: "testapp",
|
||||
logLevel: zerolog.InfoLevel,
|
||||
logRegexChecks: []*regexp.Regexp{
|
||||
regexp.MustCompile(`time":\d+,`),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Set environment variables
|
||||
for key, val := range tt.inputs.envs {
|
||||
os.Setenv(key, val)
|
||||
}
|
||||
|
||||
// Prepare config in context
|
||||
ctx := MustSetupConfigAndLogging(context.Background())
|
||||
|
||||
// Retrieve config and logger from prepared context
|
||||
cfg := config.MustFromCtx(ctx)
|
||||
logger := zerolog.Ctx(ctx)
|
||||
|
||||
// Check wants
|
||||
if cfg.Name != tt.want.appName {
|
||||
t.Errorf("Expected app name %s, got %s", tt.want.appName, cfg.Name)
|
||||
}
|
||||
if logger.GetLevel() != tt.want.logLevel {
|
||||
t.Errorf("Expected log level %#v, got %#v", tt.want.logLevel, logger.GetLevel())
|
||||
}
|
||||
|
||||
// Send and capture a log
|
||||
r, w := io.Pipe()
|
||||
testLogger := logger.Output(w)
|
||||
scanner := bufio.NewScanner(r)
|
||||
|
||||
go func() {
|
||||
testLogger.Error().Msg("test message")
|
||||
w.Close()
|
||||
}()
|
||||
|
||||
logOut := make([]byte, 0)
|
||||
if scanner.Scan() {
|
||||
logOut = scanner.Bytes()
|
||||
}
|
||||
|
||||
// Check all expressions
|
||||
for _, expr := range tt.want.logRegexChecks {
|
||||
if !expr.Match(logOut) {
|
||||
t.Errorf("Regex %s did not match log %s", expr.String(), logOut)
|
||||
}
|
||||
}
|
||||
|
||||
// Super annoying need to reset due to app framework package
|
||||
// using flag.Parse() and go test also using it
|
||||
testlog := flag.Lookup("test.testlogfile").Value.String()
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
flag.String("test.testlogfile", testlog, "")
|
||||
flag.String("test.paniconexit0", "", "")
|
||||
flag.String("test.v", "", "")
|
||||
flag.Parse()
|
||||
})
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -61,9 +62,110 @@ func Test_loadConfig(t *testing.T) {
|
||||
want: testDefaultConfig,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Load from file",
|
||||
args: args{configPath: "./testdata/config.yaml"},
|
||||
want: &AppConfig{
|
||||
Name: "test-app",
|
||||
Environment: "development",
|
||||
Version: getVersion(),
|
||||
Logging: &LogConfig{
|
||||
Enabled: true,
|
||||
Level: "debug",
|
||||
Format: LogFormatJSON,
|
||||
Output: "stderr",
|
||||
TimeFormat: TimeFormatLong,
|
||||
},
|
||||
HTTP: &HTTPConfig{
|
||||
Enabled: true,
|
||||
Listen: "127.0.0.1:9090",
|
||||
LogRequests: false,
|
||||
ReadTimeout: "10s",
|
||||
WriteTimeout: "10s",
|
||||
IdleTimeout: "1m",
|
||||
},
|
||||
GRPC: &GRPCConfig{
|
||||
Enabled: false,
|
||||
Listen: "127.0.0.1:8081",
|
||||
LogRequests: false,
|
||||
EnableReflection: true,
|
||||
EnableInstrumentation: true,
|
||||
},
|
||||
OTEL: &OTELConfig{
|
||||
Enabled: true,
|
||||
PrometheusEnabled: true,
|
||||
PrometheusPath: "/metrics",
|
||||
StdoutEnabled: false,
|
||||
MetricIntervalSecs: 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Load from env",
|
||||
args: args{configPath: ""},
|
||||
want: &AppConfig{
|
||||
Name: "test-app-env",
|
||||
Environment: "production",
|
||||
Version: getVersion(),
|
||||
Logging: &LogConfig{
|
||||
Enabled: false,
|
||||
Level: "error",
|
||||
Format: LogFormatConsole,
|
||||
Output: "stdout",
|
||||
TimeFormat: TimeFormatUnix,
|
||||
},
|
||||
HTTP: &HTTPConfig{
|
||||
Enabled: false,
|
||||
Listen: "0.0.0.0:80",
|
||||
LogRequests: true,
|
||||
ReadTimeout: "15s",
|
||||
WriteTimeout: "15s",
|
||||
IdleTimeout: "2m",
|
||||
},
|
||||
GRPC: &GRPCConfig{
|
||||
Enabled: true,
|
||||
Listen: "0.0.0.0:443",
|
||||
LogRequests: true,
|
||||
EnableReflection: false,
|
||||
EnableInstrumentation: false,
|
||||
},
|
||||
OTEL: &OTELConfig{
|
||||
Enabled: false,
|
||||
PrometheusEnabled: false,
|
||||
PrometheusPath: "/metricsz",
|
||||
StdoutEnabled: true,
|
||||
MetricIntervalSecs: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.name == "Load from env" {
|
||||
os.Setenv("APP_NAME", "test-app-env")
|
||||
os.Setenv("APP_ENVIRONMENT", "production")
|
||||
os.Setenv("APP_LOG_ENABLED", "false")
|
||||
os.Setenv("APP_LOG_LEVEL", "error")
|
||||
os.Setenv("APP_LOG_FORMAT", "console")
|
||||
os.Setenv("APP_LOG_OUTPUT", "stdout")
|
||||
os.Setenv("APP_LOG_TIME_FORMAT", "unix")
|
||||
os.Setenv("APP_HTTP_ENABLED", "false")
|
||||
os.Setenv("APP_HTTP_LISTEN", "0.0.0.0:80")
|
||||
os.Setenv("APP_HTTP_LOG_REQUESTS", "true")
|
||||
os.Setenv("APP_HTTP_READ_TIMEOUT", "15s")
|
||||
os.Setenv("APP_HTTP_WRITE_TIMEOUT", "15s")
|
||||
os.Setenv("APP_HTTP_IDLE_TIMEOUT", "2m")
|
||||
os.Setenv("APP_GRPC_ENABLED", "true")
|
||||
os.Setenv("APP_GRPC_LISTEN", "0.0.0.0:443")
|
||||
os.Setenv("APP_GRPC_LOG_REQUESTS", "true")
|
||||
os.Setenv("APP_GRPC_ENABLE_REFLECTION", "false")
|
||||
os.Setenv("APP_GRPC_ENABLE_INSTRUMENTATION", "false")
|
||||
os.Setenv("APP_OTEL_ENABLED", "false")
|
||||
os.Setenv("APP_OTEL_PROMETHEUS_ENABLED", "false")
|
||||
os.Setenv("APP_OTEL_PROMETHEUS_PATH", "/metricsz")
|
||||
os.Setenv("APP_OTEL_STDOUT_ENABLED", "true")
|
||||
os.Setenv("APP_OTEL_METRIC_INTERVAL_SECS", "60")
|
||||
}
|
||||
got, err := loadConfig(tt.args.configPath)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("loadConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
5
pkg/config/testdata/config.yaml
vendored
Normal file
5
pkg/config/testdata/config.yaml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
name: test-app
|
||||
logging:
|
||||
level: debug
|
||||
http:
|
||||
listen: "127.0.0.1:9090"
|
133
pkg/logging/logging_test.go
Normal file
133
pkg/logging/logging_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
package logging
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/config"
|
||||
)
|
||||
|
||||
func TestMustInitLogging(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Logging: &config.LogConfig{
|
||||
Level: "info",
|
||||
Format: "json",
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
|
||||
ctx = MustInitLogging(ctx)
|
||||
logger := zerolog.Ctx(ctx)
|
||||
|
||||
assert.NotNil(t, logger)
|
||||
assert.Equal(t, zerolog.InfoLevel, logger.GetLevel())
|
||||
}
|
||||
|
||||
func TestConfigureLogger(t *testing.T) {
|
||||
type args struct {
|
||||
cfg *config.LogConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
level zerolog.Level
|
||||
wantJSON bool
|
||||
wantTime bool
|
||||
assertion func(t *testing.T, output string)
|
||||
}{
|
||||
{
|
||||
name: "json logger",
|
||||
args: args{
|
||||
cfg: &config.LogConfig{
|
||||
Level: "debug",
|
||||
Format: "json",
|
||||
},
|
||||
},
|
||||
level: zerolog.DebugLevel,
|
||||
wantJSON: true,
|
||||
},
|
||||
{
|
||||
name: "console logger",
|
||||
args: args{
|
||||
cfg: &config.LogConfig{
|
||||
Level: "warn",
|
||||
Format: "console",
|
||||
},
|
||||
},
|
||||
level: zerolog.WarnLevel,
|
||||
wantJSON: false,
|
||||
},
|
||||
{
|
||||
name: "with time",
|
||||
args: args{
|
||||
cfg: &config.LogConfig{
|
||||
Level: "info",
|
||||
Format: "json",
|
||||
TimeFormat: "unix",
|
||||
},
|
||||
},
|
||||
level: zerolog.InfoLevel,
|
||||
wantJSON: true,
|
||||
wantTime: true,
|
||||
assertion: func(t *testing.T, output string) {
|
||||
var log map[string]interface{}
|
||||
err := json.Unmarshal([]byte(output), &log)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, log, "time")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "without time",
|
||||
args: args{
|
||||
cfg: &config.LogConfig{
|
||||
Level: "info",
|
||||
Format: "json",
|
||||
TimeFormat: "off",
|
||||
},
|
||||
},
|
||||
level: zerolog.InfoLevel,
|
||||
wantJSON: true,
|
||||
wantTime: false,
|
||||
assertion: func(t *testing.T, output string) {
|
||||
var log map[string]interface{}
|
||||
err := json.Unmarshal([]byte(output), &log)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, log, "time")
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Capture output
|
||||
old := os.Stderr
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stderr = w
|
||||
|
||||
logger, err := configureLogger(tt.args.cfg)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.level, logger.GetLevel())
|
||||
|
||||
logger.Info().Msg("test")
|
||||
|
||||
w.Close()
|
||||
os.Stderr = old
|
||||
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
|
||||
output := buf.String()
|
||||
|
||||
if tt.assertion != nil {
|
||||
tt.assertion(t, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
66
pkg/otel/otel_test.go
Normal file
66
pkg/otel/otel_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
package otel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.opentelemetry.io/otel/metric/noop"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/config"
|
||||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Name: "test-app",
|
||||
OTEL: &config.OTELConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
|
||||
ctx, shutdown := Init(ctx)
|
||||
defer shutdown(context.Background())
|
||||
|
||||
assert.NotNil(t, ctx.Value(ctxKeyTracer))
|
||||
assert.NotNil(t, ctx.Value(ctxKeyMeter))
|
||||
}
|
||||
|
||||
func TestInit_Disabled(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Name: "test-app",
|
||||
OTEL: &config.OTELConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
|
||||
ctx, shutdown := Init(ctx)
|
||||
defer shutdown(context.Background())
|
||||
|
||||
assert.NotNil(t, ctx.Value(ctxKeyTracer))
|
||||
assert.NotNil(t, ctx.Value(ctxKeyMeter))
|
||||
}
|
||||
|
||||
func TestContextFuncs(t *testing.T) {
|
||||
tracer := trace.NewNoopTracerProvider().Tracer("test")
|
||||
meter := noop.NewMeterProvider().Meter("test")
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = AddTracerToCtx(ctx, tracer)
|
||||
ctx = AddMeterToCtx(ctx, meter)
|
||||
|
||||
assert.Equal(t, tracer, MustTracerFromCtx(ctx))
|
||||
assert.Equal(t, meter, MustMeterFromCtx(ctx))
|
||||
}
|
||||
|
||||
func TestContextFuncs_Panic(t *testing.T) {
|
||||
assert.Panics(t, func() {
|
||||
MustTracerFromCtx(context.Background())
|
||||
})
|
||||
assert.Panics(t, func() {
|
||||
MustMeterFromCtx(context.Background())
|
||||
})
|
||||
}
|
111
pkg/srv/grpc/grpc_test.go
Normal file
111
pkg/srv/grpc/grpc_test.go
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/config"
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/otel"
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/grpc/opts"
|
||||
)
|
||||
|
||||
// Mock gRPC service
|
||||
type mockService struct{}
|
||||
|
||||
type MockServiceServer interface {
|
||||
TestMethod(context.Context, *mockRequest) (*mockResponse, error)
|
||||
}
|
||||
|
||||
type mockRequest struct{}
|
||||
type mockResponse struct{}
|
||||
|
||||
func (s *mockService) TestMethod(ctx context.Context, req *mockRequest) (*mockResponse, error) {
|
||||
return &mockResponse{}, nil
|
||||
}
|
||||
|
||||
var _MockService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "test.MockService",
|
||||
HandlerType: (*MockServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "TestMethod",
|
||||
Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(mockRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MockServiceServer).TestMethod(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/test.MockService/TestMethod",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MockServiceServer).TestMethod(ctx, req.(*mockRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
},
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "mock.proto",
|
||||
}
|
||||
|
||||
func TestInitGRPCServer(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Name: "test-app",
|
||||
GRPC: &config.GRPCConfig{
|
||||
Enabled: true,
|
||||
Listen: "127.0.0.1:0", // Use random available port
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
ctx, _ = otel.Init(ctx)
|
||||
|
||||
grpcOpts := &opts.GRPCOpts{
|
||||
GRPCConfig: cfg.GRPC,
|
||||
AppGRPC: &opts.AppGRPC{
|
||||
Services: []*opts.GRPCService{
|
||||
{
|
||||
Name: "mock",
|
||||
Type: &_MockService_serviceDesc,
|
||||
Service: &mockService{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
shutdown, done, err := InitGRPCServer(ctx, grpcOpts)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, shutdown)
|
||||
assert.NotNil(t, done)
|
||||
|
||||
// Shutdown the server
|
||||
err = shutdown(context.Background())
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInitGRPCServer_NoServices(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Name: "test-app",
|
||||
GRPC: &config.GRPCConfig{
|
||||
Enabled: true,
|
||||
Listen: "127.0.0.1:0",
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
ctx, _ = otel.Init(ctx)
|
||||
|
||||
grpcOpts := &opts.GRPCOpts{
|
||||
GRPCConfig: cfg.GRPC,
|
||||
AppGRPC: &opts.AppGRPC{},
|
||||
}
|
||||
|
||||
_, _, err := InitGRPCServer(ctx, grpcOpts)
|
||||
assert.Error(t, err)
|
||||
}
|
88
pkg/srv/http/http_test.go
Normal file
88
pkg/srv/http/http_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/config"
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/otel"
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/http/opts"
|
||||
)
|
||||
|
||||
func TestInitHTTPServer(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Name: "test-app",
|
||||
HTTP: &config.HTTPConfig{
|
||||
Enabled: true,
|
||||
Listen: "127.0.0.1:0", // Use random available port
|
||||
},
|
||||
OTEL: &config.OTELConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
ctx, _ = otel.Init(ctx)
|
||||
|
||||
httpOpts := &opts.AppHTTP{
|
||||
Ctx: ctx,
|
||||
Funcs: []opts.HTTPFunc{
|
||||
{
|
||||
Path: "/test",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
shutdown, done, err := InitHTTPServer(httpOpts)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, shutdown)
|
||||
assert.NotNil(t, done)
|
||||
|
||||
// Shutdown the server
|
||||
err = shutdown(context.Background())
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHealthCheck(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/health", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handleHealthCheckFunc(context.Background())(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
assert.Equal(t, "ok", string(body))
|
||||
}
|
||||
|
||||
func TestLoggingMiddleware(t *testing.T) {
|
||||
cfg := &config.AppConfig{
|
||||
Name: "test-app",
|
||||
HTTP: &config.HTTPConfig{
|
||||
LogRequests: true,
|
||||
},
|
||||
}
|
||||
ctx := cfg.AddToCtx(context.Background())
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
middleware := loggingMiddleware(ctx, handler)
|
||||
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
middleware.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
Reference in New Issue
Block a user