Browse Source

test: Add unit tests for chat storage and environment utilities

pull/280/head
Aldino Kemal 12 months ago
parent
commit
069ed9ca1c
  1. 155
      src/pkg/utils/chat_storage_test.go
  2. 185
      src/pkg/utils/environment_test.go

155
src/pkg/utils/chat_storage_test.go

@ -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))
}

185
src/pkg/utils/environment_test.go

@ -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))
}
Loading…
Cancel
Save