2 changed files with 340 additions and 0 deletions
@ -0,0 +1,155 @@ |
|||
package utils_test |
|||
|
|||
import ( |
|||
"encoding/csv" |
|||
"os" |
|||
"path/filepath" |
|||
"testing" |
|||
|
|||
"github.com/aldinokemal/go-whatsapp-web-multidevice/config" |
|||
. "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils" |
|||
"github.com/stretchr/testify/assert" |
|||
"github.com/stretchr/testify/suite" |
|||
) |
|||
|
|||
type ChatStorageTestSuite struct { |
|||
suite.Suite |
|||
tempDir string |
|||
origStorage bool |
|||
origPath string |
|||
} |
|||
|
|||
func (suite *ChatStorageTestSuite) SetupTest() { |
|||
// Create a temporary directory for test files
|
|||
tempDir, err := os.MkdirTemp("", "chat_storage_test") |
|||
assert.NoError(suite.T(), err) |
|||
suite.tempDir = tempDir |
|||
|
|||
// Save original config values
|
|||
suite.origStorage = config.WhatsappChatStorage |
|||
suite.origPath = config.PathChatStorage |
|||
|
|||
// Set test config values
|
|||
config.WhatsappChatStorage = true |
|||
config.PathChatStorage = filepath.Join(tempDir, "chat_storage.csv") |
|||
} |
|||
|
|||
func (suite *ChatStorageTestSuite) TearDownTest() { |
|||
// Restore original config values
|
|||
config.WhatsappChatStorage = suite.origStorage |
|||
config.PathChatStorage = suite.origPath |
|||
|
|||
// Clean up temp directory
|
|||
os.RemoveAll(suite.tempDir) |
|||
} |
|||
|
|||
func (suite *ChatStorageTestSuite) createTestData() { |
|||
// Create test CSV data
|
|||
file, err := os.Create(config.PathChatStorage) |
|||
assert.NoError(suite.T(), err) |
|||
defer file.Close() |
|||
|
|||
writer := csv.NewWriter(file) |
|||
defer writer.Flush() |
|||
|
|||
testData := [][]string{ |
|||
{"msg1", "user1@test.com", "Hello world"}, |
|||
{"msg2", "user2@test.com", "Test message"}, |
|||
} |
|||
|
|||
err = writer.WriteAll(testData) |
|||
assert.NoError(suite.T(), err) |
|||
} |
|||
|
|||
func (suite *ChatStorageTestSuite) TestFindRecordFromStorage() { |
|||
// Test case: Record found
|
|||
suite.createTestData() |
|||
record, err := FindRecordFromStorage("msg1") |
|||
assert.NoError(suite.T(), err) |
|||
assert.Equal(suite.T(), "msg1", record.MessageID) |
|||
assert.Equal(suite.T(), "user1@test.com", record.JID) |
|||
assert.Equal(suite.T(), "Hello world", record.MessageContent) |
|||
|
|||
// Test case: Record not found
|
|||
_, err = FindRecordFromStorage("non_existent") |
|||
assert.Error(suite.T(), err) |
|||
assert.Contains(suite.T(), err.Error(), "not found in storage") |
|||
|
|||
// Test case: Empty file - should still report message not found
|
|||
os.Remove(config.PathChatStorage) |
|||
_, err = FindRecordFromStorage("msg1") |
|||
assert.Error(suite.T(), err) |
|||
assert.Contains(suite.T(), err.Error(), "not found in storage") |
|||
|
|||
// Test case: Corrupted CSV file - should return CSV parsing error
|
|||
err = os.WriteFile(config.PathChatStorage, []byte("corrupted,csv,data\nwith,no,proper,format"), 0644) |
|||
assert.NoError(suite.T(), err) |
|||
_, err = FindRecordFromStorage("msg1") |
|||
assert.Error(suite.T(), err) |
|||
assert.Contains(suite.T(), err.Error(), "failed to read CSV records") |
|||
|
|||
// Test case: File permissions issue
|
|||
// Create an unreadable directory for testing file permission issues
|
|||
unreadableDir := filepath.Join(suite.tempDir, "unreadable") |
|||
err = os.Mkdir(unreadableDir, 0000) |
|||
assert.NoError(suite.T(), err) |
|||
defer os.Chmod(unreadableDir, 0755) // So it can be deleted during teardown
|
|||
|
|||
// Temporarily change path to unreadable location
|
|||
origPath := config.PathChatStorage |
|||
config.PathChatStorage = filepath.Join(unreadableDir, "inaccessible.csv") |
|||
_, err = FindRecordFromStorage("anything") |
|||
assert.Error(suite.T(), err) |
|||
assert.Contains(suite.T(), err.Error(), "failed to open storage file") |
|||
|
|||
// Restore path
|
|||
config.PathChatStorage = origPath |
|||
} |
|||
|
|||
func (suite *ChatStorageTestSuite) TestRecordMessage() { |
|||
// Test case: Normal recording
|
|||
err := RecordMessage("newMsg", "user@test.com", "New test message") |
|||
assert.NoError(suite.T(), err) |
|||
|
|||
// Verify the message was recorded
|
|||
record, err := FindRecordFromStorage("newMsg") |
|||
assert.NoError(suite.T(), err) |
|||
assert.Equal(suite.T(), "newMsg", record.MessageID) |
|||
assert.Equal(suite.T(), "user@test.com", record.JID) |
|||
assert.Equal(suite.T(), "New test message", record.MessageContent) |
|||
|
|||
// Test case: Duplicate message ID
|
|||
err = RecordMessage("newMsg", "user@test.com", "Duplicate message") |
|||
assert.NoError(suite.T(), err) |
|||
|
|||
// Verify the duplicate wasn't added
|
|||
record, err = FindRecordFromStorage("newMsg") |
|||
assert.NoError(suite.T(), err) |
|||
assert.Equal(suite.T(), "New test message", record.MessageContent, "Should not update existing record") |
|||
|
|||
// Test case: Disabled storage
|
|||
config.WhatsappChatStorage = false |
|||
err = RecordMessage("anotherMsg", "user@test.com", "Should not be stored") |
|||
assert.NoError(suite.T(), err) |
|||
|
|||
config.WhatsappChatStorage = true // Re-enable for next tests
|
|||
_, err = FindRecordFromStorage("anotherMsg") |
|||
assert.Error(suite.T(), err, "Message should not be found when storage is disabled") |
|||
|
|||
// Test case: Write permission error - Alternative approach to avoid platform-specific issues
|
|||
// Instead of creating an unwritable file, we'll temporarily set PathChatStorage to a non-existent directory
|
|||
nonExistentPath := filepath.Join(suite.tempDir, "non-existent-dir", "test.csv") |
|||
origPath := config.PathChatStorage |
|||
config.PathChatStorage = nonExistentPath |
|||
|
|||
err = RecordMessage("failMsg", "user@test.com", "Should fail to write") |
|||
assert.Error(suite.T(), err) |
|||
assert.Contains(suite.T(), err.Error(), "failed to open file for writing") |
|||
|
|||
// Restore path
|
|||
config.PathChatStorage = origPath |
|||
} |
|||
|
|||
func TestChatStorageTestSuite(t *testing.T) { |
|||
suite.Run(t, new(ChatStorageTestSuite)) |
|||
} |
|||
@ -0,0 +1,185 @@ |
|||
package utils_test |
|||
|
|||
import ( |
|||
"os" |
|||
"testing" |
|||
"time" |
|||
|
|||
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils" |
|||
"github.com/spf13/viper" |
|||
"github.com/stretchr/testify/assert" |
|||
"github.com/stretchr/testify/suite" |
|||
) |
|||
|
|||
type EnvironmentTestSuite struct { |
|||
suite.Suite |
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) SetupTest() { |
|||
// Clear any existing viper configs
|
|||
viper.Reset() |
|||
// Set up automatic environment variable reading
|
|||
viper.AutomaticEnv() |
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TearDownTest() { |
|||
viper.Reset() |
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestIsLocal() { |
|||
tests := []struct { |
|||
name string |
|||
envValue string |
|||
expected bool |
|||
}{ |
|||
{"Production environment", "production", false}, |
|||
{"Staging environment", "staging", false}, |
|||
{"Integration environment", "integration", false}, |
|||
{"Development environment", "development", true}, |
|||
{"Local environment", "local", true}, |
|||
} |
|||
|
|||
for _, tt := range tests { |
|||
suite.T().Run(tt.name, func(t *testing.T) { |
|||
// Set the environment value
|
|||
if tt.envValue != "" { |
|||
viper.Set("APP_ENV", tt.envValue) |
|||
} else { |
|||
viper.Set("APP_ENV", nil) // Explicitly clear the value
|
|||
} |
|||
|
|||
result := utils.IsLocal() |
|||
assert.Equal(t, tt.expected, result) |
|||
}) |
|||
} |
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestEnv() { |
|||
// Test with existing value
|
|||
viper.Set("TEST_KEY", "test_value") |
|||
result := utils.Env[string]("TEST_KEY") |
|||
assert.Equal(suite.T(), "test_value", result) |
|||
|
|||
// Test with default value
|
|||
result = utils.Env("NON_EXISTENT_KEY", "default_value") |
|||
assert.Equal(suite.T(), "default_value", result) |
|||
|
|||
// Test with integer
|
|||
viper.Set("TEST_INT", 42) |
|||
intResult := utils.Env[int]("TEST_INT") |
|||
assert.Equal(suite.T(), 42, intResult) |
|||
|
|||
// Test with default integer
|
|||
intResult = utils.Env("NON_EXISTENT_INT", 100) |
|||
assert.Equal(suite.T(), 100, intResult) |
|||
|
|||
// Test with boolean
|
|||
viper.Set("TEST_BOOL", true) |
|||
boolResult := utils.Env[bool]("TEST_BOOL") |
|||
assert.Equal(suite.T(), true, boolResult) |
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestMustHaveEnv() { |
|||
// Test with value present
|
|||
viper.Set("REQUIRED_ENV", "required_value") |
|||
result := utils.MustHaveEnv("REQUIRED_ENV") |
|||
assert.Equal(suite.T(), "required_value", result) |
|||
|
|||
// Create a temporary .env file for testing
|
|||
tempEnvContent := []byte("ENV_FROM_FILE=env_file_value\n") |
|||
err := os.WriteFile(".env", tempEnvContent, 0644) |
|||
assert.NoError(suite.T(), err) |
|||
defer os.Remove(".env") |
|||
|
|||
// Test reading from .env file
|
|||
result = utils.MustHaveEnv("ENV_FROM_FILE") |
|||
assert.Equal(suite.T(), "env_file_value", result) |
|||
|
|||
// We can't easily test the fatal log scenario in a unit test
|
|||
// as it would terminate the program
|
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestMustHaveEnvBool() { |
|||
// Test true value
|
|||
viper.Set("BOOL_TRUE", "true") |
|||
result := utils.MustHaveEnvBool("BOOL_TRUE") |
|||
assert.True(suite.T(), result) |
|||
|
|||
// Test false value
|
|||
viper.Set("BOOL_FALSE", "false") |
|||
result = utils.MustHaveEnvBool("BOOL_FALSE") |
|||
assert.False(suite.T(), result) |
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestMustHaveEnvInt() { |
|||
// Test valid integer
|
|||
viper.Set("INT_VALUE", "42") |
|||
result := utils.MustHaveEnvInt("INT_VALUE") |
|||
assert.Equal(suite.T(), 42, result) |
|||
|
|||
// Test zero
|
|||
viper.Set("ZERO_INT", "0") |
|||
result = utils.MustHaveEnvInt("ZERO_INT") |
|||
assert.Equal(suite.T(), 0, result) |
|||
|
|||
// Test negative number
|
|||
viper.Set("NEG_INT", "-10") |
|||
result = utils.MustHaveEnvInt("NEG_INT") |
|||
assert.Equal(suite.T(), -10, result) |
|||
|
|||
// We can't easily test the fatal log scenario with invalid int
|
|||
// as it would terminate the program
|
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestMustHaveEnvMinuteDuration() { |
|||
// Test valid duration
|
|||
viper.Set("DURATION_MIN", "5") |
|||
result := utils.MustHaveEnvMinuteDuration("DURATION_MIN") |
|||
assert.Equal(suite.T(), 5*time.Minute, result) |
|||
|
|||
// Test zero duration
|
|||
viper.Set("ZERO_DURATION", "0") |
|||
result = utils.MustHaveEnvMinuteDuration("ZERO_DURATION") |
|||
assert.Equal(suite.T(), 0*time.Minute, result) |
|||
|
|||
// We can't easily test the fatal log scenario with invalid duration
|
|||
// as it would terminate the program
|
|||
} |
|||
|
|||
func (suite *EnvironmentTestSuite) TestLoadConfig() { |
|||
// Create a temporary config file for testing
|
|||
tempDir, err := os.MkdirTemp("", "config_test") |
|||
assert.NoError(suite.T(), err) |
|||
defer os.RemoveAll(tempDir) |
|||
|
|||
// Create test config file
|
|||
configContent := []byte("TEST_CONFIG=config_value\n") |
|||
configPath := tempDir + "/.env" |
|||
err = os.WriteFile(configPath, configContent, 0644) |
|||
assert.NoError(suite.T(), err) |
|||
|
|||
// Test loading config with default name
|
|||
err = utils.LoadConfig(tempDir) |
|||
assert.NoError(suite.T(), err) |
|||
assert.Equal(suite.T(), "config_value", viper.GetString("TEST_CONFIG")) |
|||
|
|||
// Test loading config with custom name
|
|||
customConfigContent := []byte("CUSTOM_CONFIG=custom_value\n") |
|||
customConfigPath := tempDir + "/custom.env" |
|||
err = os.WriteFile(customConfigPath, customConfigContent, 0644) |
|||
assert.NoError(suite.T(), err) |
|||
|
|||
viper.Reset() |
|||
err = utils.LoadConfig(tempDir, "custom") |
|||
assert.NoError(suite.T(), err) |
|||
assert.Equal(suite.T(), "custom_value", viper.GetString("CUSTOM_CONFIG")) |
|||
|
|||
// Test error case - non-existent directory
|
|||
viper.Reset() |
|||
err = utils.LoadConfig("/non/existent/directory") |
|||
assert.Error(suite.T(), err) |
|||
} |
|||
|
|||
func TestEnvironmentTestSuite(t *testing.T) { |
|||
suite.Run(t, new(EnvironmentTestSuite)) |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue