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 }