Added test case for Adapter
1. Removed config files from config folder. 2. Added test cases for the Adapter with code coverage of 91%. 3. Resolved linting issues.
This commit is contained in:
@@ -19,8 +19,8 @@ import (
|
||||
"github.com/beckn/beckn-onix/pkg/plugin"
|
||||
)
|
||||
|
||||
// config struct holds all configurations.
|
||||
type config struct {
|
||||
// Config struct holds all configurations.
|
||||
type Config struct {
|
||||
AppName string `yaml:"appName"`
|
||||
Log log.Config `yaml:"log"`
|
||||
PluginManager *plugin.ManagerConfig `yaml:"pluginManager"`
|
||||
@@ -40,6 +40,7 @@ type timeoutConfig struct {
|
||||
}
|
||||
|
||||
var configPath string
|
||||
var runFunc = run
|
||||
|
||||
func main() {
|
||||
// Define and parse command-line flags.
|
||||
@@ -50,14 +51,14 @@ func main() {
|
||||
log.Infof(context.Background(), "Starting application with config: %s", configPath)
|
||||
|
||||
// Run the application within a context.
|
||||
if err := run(context.Background(), configPath); err != nil {
|
||||
if err := runFunc(context.Background(), configPath); err != nil {
|
||||
log.Fatalf(context.Background(), err, "Application failed: %v", err)
|
||||
}
|
||||
log.Infof(context.Background(), "Application finished")
|
||||
}
|
||||
|
||||
// initConfig loads and validates the configuration.
|
||||
func initConfig(ctx context.Context, path string) (*config, error) {
|
||||
func initConfig(ctx context.Context, path string) (*Config, error) {
|
||||
// Open the configuration file.
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
@@ -66,7 +67,7 @@ func initConfig(ctx context.Context, path string) (*config, error) {
|
||||
defer file.Close()
|
||||
|
||||
// Decode the YAML configuration.
|
||||
var cfg config
|
||||
var cfg Config
|
||||
if err := yaml.NewDecoder(file).Decode(&cfg); err != nil {
|
||||
return nil, fmt.Errorf("could not decode config: %w", err)
|
||||
}
|
||||
@@ -80,7 +81,7 @@ func initConfig(ctx context.Context, path string) (*config, error) {
|
||||
}
|
||||
|
||||
// validateConfig validates the configuration.
|
||||
func validateConfig(cfg *config) error {
|
||||
func validateConfig(cfg *Config) error {
|
||||
if strings.TrimSpace(cfg.AppName) == "" {
|
||||
return fmt.Errorf("missing app name")
|
||||
}
|
||||
@@ -91,7 +92,7 @@ func validateConfig(cfg *config) error {
|
||||
}
|
||||
|
||||
// newServer creates and initializes the HTTP server.
|
||||
func newServer(ctx context.Context, mgr handler.PluginManager, cfg *config) (http.Handler, error) {
|
||||
func newServer(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error) {
|
||||
mux := http.NewServeMux()
|
||||
err := module.Register(ctx, cfg.Modules, mux, mgr)
|
||||
if err != nil {
|
||||
@@ -100,6 +101,10 @@ func newServer(ctx context.Context, mgr handler.PluginManager, cfg *config) (htt
|
||||
return mux, nil
|
||||
}
|
||||
|
||||
var newManagerFunc = plugin.NewManager
|
||||
var newServerFunc = newServer
|
||||
var initLoggerFunc = log.InitLogger
|
||||
|
||||
// run encapsulates the application logic.
|
||||
func run(ctx context.Context, configPath string) error {
|
||||
closers := []func(){}
|
||||
@@ -109,13 +114,13 @@ func run(ctx context.Context, configPath string) error {
|
||||
return fmt.Errorf("failed to initialize config: %w", err)
|
||||
}
|
||||
log.Infof(ctx, "Initializing logger with config: %+v", cfg.Log)
|
||||
if err := log.InitLogger(cfg.Log); err != nil {
|
||||
if err := initLoggerFunc(cfg.Log); err != nil {
|
||||
return fmt.Errorf("failed to initialize logger: %w", err)
|
||||
}
|
||||
|
||||
// Initialize plugin manager.
|
||||
log.Infof(ctx, "Initializing plugin manager")
|
||||
mgr, closer, err := plugin.NewManager(ctx, cfg.PluginManager)
|
||||
mgr, closer, err := newManagerFunc(ctx, cfg.PluginManager)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create plugin manager: %w", err)
|
||||
}
|
||||
@@ -124,7 +129,7 @@ func run(ctx context.Context, configPath string) error {
|
||||
|
||||
// Initialize HTTP server.
|
||||
log.Infof(ctx, "Initializing HTTP server")
|
||||
srv, err := newServer(ctx, mgr, cfg)
|
||||
srv, err := newServerFunc(ctx, mgr, cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize server: %w", err)
|
||||
}
|
||||
|
||||
514
cmd/adapter/main_test.go
Normal file
514
cmd/adapter/main_test.go
Normal file
@@ -0,0 +1,514 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/beckn/beckn-onix/core/module"
|
||||
"github.com/beckn/beckn-onix/core/module/handler"
|
||||
"github.com/beckn/beckn-onix/pkg/plugin"
|
||||
"github.com/beckn/beckn-onix/pkg/plugin/definition"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockPluginManager implements handler.PluginManager for testing.
|
||||
type MockPluginManager struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Middleware returns a middleware function based on the provided configuration.
|
||||
func (m *MockPluginManager) Middleware(ctx context.Context, cfg *plugin.Config) (func(http.Handler) http.Handler, error) {
|
||||
args := m.Called(ctx, cfg)
|
||||
return args.Get(0).(func(http.Handler) http.Handler), args.Error(1)
|
||||
}
|
||||
|
||||
// SignValidator returns a mock implementation of the Verifier interface.
|
||||
func (m *MockPluginManager) SignValidator(ctx context.Context, cfg *plugin.Config) (definition.Verifier, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Validator returns a mock implementation of the SchemaValidator interface.
|
||||
func (m *MockPluginManager) Validator(ctx context.Context, cfg *plugin.Config) (definition.SchemaValidator, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Router returns a mock implementation of the Router interface.
|
||||
func (m *MockPluginManager) Router(ctx context.Context, cfg *plugin.Config) (definition.Router, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Publisher returns a mock implementation of the Publisher interface.
|
||||
func (m *MockPluginManager) Publisher(ctx context.Context, cfg *plugin.Config) (definition.Publisher, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Signer returns a mock implementation of the Signer interface.
|
||||
func (m *MockPluginManager) Signer(ctx context.Context, cfg *plugin.Config) (definition.Signer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Step returns a mock implementation of the Step interface.
|
||||
func (m *MockPluginManager) Step(ctx context.Context, cfg *plugin.Config) (definition.Step, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Cache returns a mock implementation of the Cache interface.
|
||||
func (m *MockPluginManager) Cache(ctx context.Context, cfg *plugin.Config) (definition.Cache, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// KeyManager returns a mock implementation of the KeyManager interface.
|
||||
func (m *MockPluginManager) KeyManager(ctx context.Context, cache definition.Cache, rLookup definition.RegistryLookup, cfg *plugin.Config) (definition.KeyManager, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SchemaValidator returns a mock implementation of the SchemaValidator interface.
|
||||
func (m *MockPluginManager) SchemaValidator(ctx context.Context, cfg *plugin.Config) (definition.SchemaValidator, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// testConfigContent defines a mock configuration used in tests.
|
||||
const testConfigContent = `
|
||||
appName: "TestApp"
|
||||
http:
|
||||
port: "8080"
|
||||
timeout:
|
||||
read: 5
|
||||
write: 5
|
||||
idle: 10
|
||||
`
|
||||
|
||||
// initLogger is a mock function to initialize the logger.
|
||||
var initLogger = func(cfg *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mockRun is a mock implementation of the `run` function, simulating a successful run.
|
||||
func mockRun(ctx context.Context, configPath string) error {
|
||||
return nil // Simulate a successful run
|
||||
}
|
||||
|
||||
// TestMainFunction tests the main function execution, including command-line argument parsing.
|
||||
func TestMainFunction(t *testing.T) {
|
||||
// Backup original run function and restore it after test
|
||||
origRun := runFunc
|
||||
defer func() { runFunc = origRun }()
|
||||
runFunc = mockRun
|
||||
|
||||
origArgs := os.Args
|
||||
defer func() { os.Args = origArgs }()
|
||||
|
||||
// Set mock command-line arguments
|
||||
os.Args = []string{"cmd", "-config=../../config/test-config.yaml"}
|
||||
|
||||
fs := flag.NewFlagSet("test", flag.ExitOnError)
|
||||
fs.StringVar(&configPath, "config", "../../config/clientSideHandler-config.yaml", "Path to the configuration file")
|
||||
|
||||
fs.Parse(os.Args[1:])
|
||||
main()
|
||||
}
|
||||
|
||||
// TestRunSuccess tests the successful execution of the run function with different configurations.
|
||||
func TestRunSuccess(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
configData string
|
||||
mockMgr func() (*plugin.Manager, func(), error)
|
||||
mockLogger func(cfg *Config) error
|
||||
mockServer func(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error)
|
||||
}{
|
||||
{
|
||||
name: "Valid Config",
|
||||
configData: "valid_config.yaml",
|
||||
mockMgr: func() (*plugin.Manager, func(), error) {
|
||||
return &plugin.Manager{}, func() {}, nil
|
||||
},
|
||||
mockLogger: func(cfg *Config) error {
|
||||
return nil
|
||||
},
|
||||
mockServer: func(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error) {
|
||||
return http.NewServeMux(), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
testFilePath := tt.configData
|
||||
mockConfig := `appName: "testAdapter"
|
||||
log:
|
||||
level: debug
|
||||
destinations:
|
||||
- type: stdout
|
||||
context_keys:
|
||||
- transaction_id
|
||||
- message_id
|
||||
http:
|
||||
port: 8080
|
||||
timeout:
|
||||
read: 30
|
||||
write: 30
|
||||
idle: 30
|
||||
plugin:
|
||||
root: "/mock/plugins"
|
||||
pluginZipPath: "/mock/plugins/plugins_bundle.zip"
|
||||
plugins:
|
||||
- testPlugin1
|
||||
- testPlugin2
|
||||
modules:
|
||||
- name: testModule
|
||||
type: transaction
|
||||
path: /testPath
|
||||
targetType: msgQ
|
||||
plugin:
|
||||
schemaValidator:
|
||||
id: testValidator
|
||||
publisher:
|
||||
id: testPublisher
|
||||
config:
|
||||
project: test-project
|
||||
topic: test-topic
|
||||
router:
|
||||
id: testRouter
|
||||
config:
|
||||
routingConfigPath: "/mock/configs/testRouting-config.yaml"`
|
||||
|
||||
err := os.WriteFile(testFilePath, []byte(mockConfig), 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create test config file: %v", err)
|
||||
}
|
||||
defer os.Remove(testFilePath)
|
||||
|
||||
// Mock dependencies
|
||||
originalNewManager := newManagerFunc
|
||||
newManagerFunc = func(ctx context.Context, cfg *plugin.ManagerConfig) (*plugin.Manager, func(), error) {
|
||||
return tt.mockMgr()
|
||||
}
|
||||
defer func() { newManagerFunc = originalNewManager }()
|
||||
|
||||
originalNewServer := newServerFunc
|
||||
newServerFunc = func(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error) {
|
||||
return tt.mockServer(ctx, mgr, cfg)
|
||||
}
|
||||
defer func() { newServerFunc = originalNewServer }()
|
||||
|
||||
// Run function
|
||||
err = run(ctx, testFilePath)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunFailure validates failure scenarios for the run function.
|
||||
func TestRunFailure(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
configData string
|
||||
mockMgr func() (*plugin.Manager, func(), error)
|
||||
mockLogger func(cfg *Config) error
|
||||
mockServer func(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error)
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "Invalid Config File",
|
||||
configData: "invalid_config.yaml",
|
||||
mockMgr: func() (*plugin.Manager, func(), error) {
|
||||
return &plugin.Manager{}, func() {}, nil
|
||||
},
|
||||
mockLogger: func(cfg *Config) error {
|
||||
return nil
|
||||
},
|
||||
mockServer: func(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error) {
|
||||
return nil, errors.New("failed to start server")
|
||||
},
|
||||
expectedErr: "failed to initialize config: invalid config: missing app name",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
testFilePath := tt.configData
|
||||
mockConfig := `invalid: "config"`
|
||||
err := os.WriteFile(testFilePath, []byte(mockConfig), 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create test config file: %v", err)
|
||||
}
|
||||
defer os.Remove(testFilePath)
|
||||
|
||||
// Mock dependencies
|
||||
originalNewManager := newManagerFunc
|
||||
newManagerFunc = func(ctx context.Context, cfg *plugin.ManagerConfig) (*plugin.Manager, func(), error) {
|
||||
return tt.mockMgr()
|
||||
}
|
||||
defer func() { newManagerFunc = originalNewManager }()
|
||||
|
||||
originalNewServer := newServerFunc
|
||||
newServerFunc = func(ctx context.Context, mgr handler.PluginManager, cfg *Config) (http.Handler, error) {
|
||||
return tt.mockServer(ctx, mgr, cfg)
|
||||
}
|
||||
defer func() { newServerFunc = originalNewServer }()
|
||||
|
||||
// Run function
|
||||
err = run(ctx, testFilePath)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, but got nil")
|
||||
} else if err.Error() != tt.expectedErr {
|
||||
t.Errorf("Expected error '%s', but got '%s'", tt.expectedErr, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestInitConfigSuccess tests the successful initialization of the config.
|
||||
func TestInitConfigSuccess(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
configData string
|
||||
}{
|
||||
{
|
||||
name: "Valid Config",
|
||||
configData: `
|
||||
appName: "TestApp"
|
||||
http:
|
||||
port: "8080"
|
||||
timeout:
|
||||
read: 5
|
||||
write: 5
|
||||
idle: 10
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
configPath := "test_config_success.yaml"
|
||||
defer os.Remove(configPath)
|
||||
|
||||
err := os.WriteFile(configPath, []byte(tt.configData), 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create test config file: %v", err)
|
||||
}
|
||||
|
||||
_, err = initConfig(context.Background(), configPath)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestInitConfigFailure tests failure scenarios for config initialization.
|
||||
func TestInitConfigFailure(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
configData string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "Invalid YAML Format",
|
||||
configData: `appName: "TestApp"\nhttp: { invalid_yaml }`,
|
||||
expectedErr: "could not decode config",
|
||||
},
|
||||
{
|
||||
name: "Missing Required Fields",
|
||||
configData: `appName: ""\nhttp:\n timeout:\n read: 5\n`,
|
||||
expectedErr: "could not decode config: yaml: did not find expected key",
|
||||
},
|
||||
{
|
||||
name: "Non-Existent File",
|
||||
configData: "",
|
||||
expectedErr: "could not open config file",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
configPath := "test_config_failure.yaml"
|
||||
|
||||
if tt.configData != "" {
|
||||
err := os.WriteFile(configPath, []byte(tt.configData), 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create test config file: %v", err)
|
||||
}
|
||||
defer os.Remove(configPath)
|
||||
} else {
|
||||
// Ensure file does not exist for non-existent file test
|
||||
os.Remove(configPath)
|
||||
}
|
||||
|
||||
_, err := initConfig(context.Background(), configPath)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error but got nil")
|
||||
} else if !strings.Contains(err.Error(), tt.expectedErr) {
|
||||
t.Errorf("Expected error containing '%s', but got '%s'", tt.expectedErr, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewServerSuccess tests successful server creation.
|
||||
func TestNewServerSuccess(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modules []module.Config
|
||||
}{
|
||||
{
|
||||
name: "Successful server creation with no modules",
|
||||
modules: []module.Config{}, // No modules to simplify the test
|
||||
},
|
||||
}
|
||||
|
||||
mockMgr := new(MockPluginManager) // Mocking PluginManager
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Modules: tt.modules,
|
||||
HTTP: httpConfig{
|
||||
Port: "8080",
|
||||
Timeout: timeoutConfig{
|
||||
Read: 5,
|
||||
Write: 5,
|
||||
Idle: 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
handler, err := newServer(context.Background(), mockMgr, cfg)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, but got: %v", err)
|
||||
}
|
||||
if handler == nil {
|
||||
t.Errorf("Expected handler to be non-nil, but got nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewServerFailure tests failure scenarios when creating a server.
|
||||
func TestNewServerFailure(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modules []module.Config
|
||||
}{
|
||||
{
|
||||
name: "Module registration failure",
|
||||
modules: []module.Config{
|
||||
{
|
||||
Name: "InvalidModule",
|
||||
Path: "/invalid",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockMgr := new(MockPluginManager) // Mocking PluginManager
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Modules: tt.modules,
|
||||
HTTP: httpConfig{
|
||||
Port: "8080",
|
||||
Timeout: timeoutConfig{
|
||||
Read: 5,
|
||||
Write: 5,
|
||||
Idle: 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
handler, err := newServer(context.Background(), mockMgr, cfg)
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but got nil")
|
||||
}
|
||||
if handler != nil {
|
||||
t.Errorf("Expected handler to be nil, but got a non-nil value")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateConfigSuccess tests validation of a correct config.
|
||||
func TestValidateConfigSuccess(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg Config
|
||||
}{
|
||||
{
|
||||
name: "Valid Config",
|
||||
cfg: Config{
|
||||
AppName: "TestApp",
|
||||
HTTP: httpConfig{
|
||||
Port: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateConfig(&tt.cfg)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateConfigFailure tests validation failures for incorrect config.
|
||||
func TestValidateConfigFailure(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg Config
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "Missing AppName",
|
||||
cfg: Config{
|
||||
AppName: "",
|
||||
HTTP: httpConfig{
|
||||
Port: "8080",
|
||||
},
|
||||
},
|
||||
expectedErr: "missing app name",
|
||||
},
|
||||
{
|
||||
name: "Missing Port",
|
||||
cfg: Config{
|
||||
AppName: "TestApp",
|
||||
HTTP: httpConfig{
|
||||
Port: "",
|
||||
},
|
||||
},
|
||||
expectedErr: "missing port",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateConfig(&tt.cfg)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error '%s', but got nil", tt.expectedErr)
|
||||
} else if err.Error() != tt.expectedErr {
|
||||
t.Errorf("Expected error '%s', but got '%s'", tt.expectedErr, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user