- Add package comments to all packages (pkg/config, pkg/logger, internal/*, cmd/platform)
- Fix context key warnings by using custom ContextKey type
- Export ContextKey type to avoid unexported-return warnings
- Update all context value operations to use ContextKey instead of string
- Update RequestIDKey() and UserIDKey() to return ContextKey
- Fix error checking issues (errcheck)
- Properly handle os.Chdir errors in defer statements
- Properly handle os.Setenv/os.Unsetenv errors in tests
- Fix security warnings (gosec)
- Change directory permissions from 0755 to 0750 in tests
- Change file permissions from 0644 to 0600 in tests
- Fix unused parameter warnings (revive)
- Replace unused parameters with _ in:
* RegisterLifecycleHooks lifecycle functions
* Mock logger implementations
* noOpLogger methods
- Fix type assertion issues (staticcheck)
- Remove unnecessary type assertions in tests
- Use simpler compile-time checks
- Fix exported type stuttering warning
- Add nolint directive for ConfigProvider (standard interface pattern)
- Update golangci-lint configuration
- Add version: 2 field (required for newer versions)
- Remove unsupported linters (typecheck, gosimple)
- Move formatters (gofmt, goimports) to separate formatters section
- Simplify linter list to only well-supported linters
All linting issues resolved (0 issues reported by golangci-lint).
All tests pass and code compiles successfully.
332 lines
6.9 KiB
Go
332 lines
6.9 KiB
Go
package di
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.dcentral.systems/toolz/goplt/pkg/config"
|
|
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
func TestProvideConfig(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Set environment variable
|
|
originalEnv := os.Getenv("ENVIRONMENT")
|
|
defer func() {
|
|
if err := os.Setenv("ENVIRONMENT", originalEnv); err != nil {
|
|
t.Logf("Failed to restore environment variable: %v", err)
|
|
}
|
|
}()
|
|
|
|
if err := os.Setenv("ENVIRONMENT", "development"); err != nil {
|
|
t.Fatalf("Failed to set environment variable: %v", err)
|
|
}
|
|
|
|
// Create a test app with ProvideConfig
|
|
app := fx.New(
|
|
ProvideConfig(),
|
|
fx.Invoke(func(cfg config.ConfigProvider) {
|
|
if cfg == nil {
|
|
t.Error("ConfigProvider is nil")
|
|
}
|
|
}),
|
|
)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Start the app
|
|
if err := app.Start(ctx); err != nil {
|
|
// It's okay if it fails due to missing config files
|
|
// We're just checking that the provider is registered
|
|
t.Logf("Start failed (may be expected in test env): %v", err)
|
|
}
|
|
|
|
// Stop the app
|
|
if err := app.Stop(ctx); err != nil {
|
|
t.Errorf("Stop failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProvideConfig_DefaultEnvironment(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Unset environment variable
|
|
originalEnv := os.Getenv("ENVIRONMENT")
|
|
defer func() {
|
|
if err := os.Setenv("ENVIRONMENT", originalEnv); err != nil {
|
|
t.Logf("Failed to restore environment variable: %v", err)
|
|
}
|
|
}()
|
|
|
|
if err := os.Unsetenv("ENVIRONMENT"); err != nil {
|
|
t.Fatalf("Failed to unset environment variable: %v", err)
|
|
}
|
|
|
|
// Create a test app with ProvideConfig
|
|
app := fx.New(
|
|
ProvideConfig(),
|
|
fx.Invoke(func(cfg config.ConfigProvider) {
|
|
if cfg == nil {
|
|
t.Error("ConfigProvider is nil")
|
|
}
|
|
}),
|
|
)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Start the app
|
|
if err := app.Start(ctx); err != nil {
|
|
// It's okay if it fails due to missing config files
|
|
t.Logf("Start failed (may be expected in test env): %v", err)
|
|
}
|
|
|
|
// Stop the app
|
|
if err := app.Stop(ctx); err != nil {
|
|
t.Errorf("Stop failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProvideLogger(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create a mock config provider
|
|
mockConfig := &mockConfigProvider{
|
|
values: map[string]any{
|
|
"logging.level": "info",
|
|
"logging.format": "json",
|
|
},
|
|
}
|
|
|
|
// Create a test app with ProvideLogger
|
|
app := fx.New(
|
|
fx.Provide(func() config.ConfigProvider {
|
|
return mockConfig
|
|
}),
|
|
ProvideLogger(),
|
|
fx.Invoke(func(log logger.Logger) {
|
|
if log == nil {
|
|
t.Error("Logger is nil")
|
|
}
|
|
|
|
// Test that logger works
|
|
log.Info("test message")
|
|
}),
|
|
)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Start the app
|
|
if err := app.Start(ctx); err != nil {
|
|
t.Fatalf("Start failed: %v", err)
|
|
}
|
|
|
|
// Stop the app
|
|
if err := app.Stop(ctx); err != nil {
|
|
t.Errorf("Stop failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProvideLogger_DefaultValues(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create a mock config provider with missing values
|
|
mockConfig := &mockConfigProvider{
|
|
values: map[string]any{},
|
|
}
|
|
|
|
// Create a test app with ProvideLogger
|
|
app := fx.New(
|
|
fx.Provide(func() config.ConfigProvider {
|
|
return mockConfig
|
|
}),
|
|
ProvideLogger(),
|
|
fx.Invoke(func(log logger.Logger) {
|
|
if log == nil {
|
|
t.Error("Logger is nil")
|
|
}
|
|
|
|
// Test that logger works with defaults
|
|
log.Info("test message with defaults")
|
|
}),
|
|
)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Start the app
|
|
if err := app.Start(ctx); err != nil {
|
|
t.Fatalf("Start failed: %v", err)
|
|
}
|
|
|
|
// Stop the app
|
|
if err := app.Stop(ctx); err != nil {
|
|
t.Errorf("Stop failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCoreModule(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create a test app with CoreModule
|
|
app := fx.New(
|
|
CoreModule(),
|
|
fx.Invoke(func(
|
|
cfg config.ConfigProvider,
|
|
log logger.Logger,
|
|
) {
|
|
if cfg == nil {
|
|
t.Error("ConfigProvider is nil")
|
|
}
|
|
if log == nil {
|
|
t.Error("Logger is nil")
|
|
}
|
|
}),
|
|
)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Start the app
|
|
if err := app.Start(ctx); err != nil {
|
|
// It's okay if it fails due to missing config files
|
|
t.Logf("Start failed (may be expected in test env): %v", err)
|
|
}
|
|
|
|
// Stop the app
|
|
if err := app.Stop(ctx); err != nil {
|
|
t.Errorf("Stop failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegisterLifecycleHooks(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create a mock logger
|
|
mockLogger := &mockLogger{}
|
|
|
|
// Create a test app with lifecycle hooks
|
|
app := fx.New(
|
|
fx.Provide(func() logger.Logger {
|
|
return mockLogger
|
|
}),
|
|
fx.Invoke(RegisterLifecycleHooks),
|
|
)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Start the app
|
|
if err := app.Start(ctx); err != nil {
|
|
t.Fatalf("Start failed: %v", err)
|
|
}
|
|
|
|
// Verify that OnStart was called
|
|
if !mockLogger.onStartCalled {
|
|
t.Error("OnStart hook was not called")
|
|
}
|
|
|
|
// Stop the app
|
|
if err := app.Stop(ctx); err != nil {
|
|
t.Errorf("Stop failed: %v", err)
|
|
}
|
|
|
|
// Verify that OnStop was called
|
|
if !mockLogger.onStopCalled {
|
|
t.Error("OnStop hook was not called")
|
|
}
|
|
}
|
|
|
|
// mockConfigProvider is a mock implementation of ConfigProvider for testing
|
|
type mockConfigProvider struct {
|
|
values map[string]any
|
|
}
|
|
|
|
func (m *mockConfigProvider) Get(key string) any {
|
|
return m.values[key]
|
|
}
|
|
|
|
func (m *mockConfigProvider) Unmarshal(_ any) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockConfigProvider) GetString(key string) string {
|
|
if val, ok := m.values[key]; ok {
|
|
if str, ok := val.(string); ok {
|
|
return str
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (m *mockConfigProvider) GetInt(key string) int {
|
|
if val, ok := m.values[key]; ok {
|
|
if i, ok := val.(int); ok {
|
|
return i
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (m *mockConfigProvider) GetBool(key string) bool {
|
|
if val, ok := m.values[key]; ok {
|
|
if b, ok := val.(bool); ok {
|
|
return b
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *mockConfigProvider) GetStringSlice(key string) []string {
|
|
if val, ok := m.values[key]; ok {
|
|
if slice, ok := val.([]string); ok {
|
|
return slice
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *mockConfigProvider) GetDuration(key string) time.Duration {
|
|
if val, ok := m.values[key]; ok {
|
|
if d, ok := val.(time.Duration); ok {
|
|
return d
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (m *mockConfigProvider) IsSet(key string) bool {
|
|
_, ok := m.values[key]
|
|
return ok
|
|
}
|
|
|
|
// mockLogger is a mock implementation of Logger for testing
|
|
type mockLogger struct {
|
|
onStartCalled bool
|
|
onStopCalled bool
|
|
}
|
|
|
|
func (m *mockLogger) Debug(_ string, _ ...logger.Field) {}
|
|
func (m *mockLogger) Info(msg string, _ ...logger.Field) {
|
|
if msg == "Application starting" {
|
|
m.onStartCalled = true
|
|
}
|
|
if msg == "Application shutting down" {
|
|
m.onStopCalled = true
|
|
}
|
|
}
|
|
func (m *mockLogger) Warn(_ string, _ ...logger.Field) {}
|
|
func (m *mockLogger) Error(_ string, _ ...logger.Field) {}
|
|
func (m *mockLogger) With(_ ...logger.Field) logger.Logger {
|
|
return m
|
|
}
|
|
func (m *mockLogger) WithContext(_ context.Context) logger.Logger {
|
|
return m
|
|
}
|