package smb import ( "testing" "github.com/stretchr/testify/suite" ) type SMBStorageTestSuite struct { suite.Suite } func TestSMBStorageTestSuite(t *testing.T) { suite.Run(t, new(SMBStorageTestSuite)) } func (s *SMBStorageTestSuite) TestNewSMBStorage() { tests := []struct { name string errorMsg string config Config expectError bool }{ { name: "valid config", config: Config{ Host: "fileserver.example.com", Port: 445, Share: "gohoarder", Path: "packages", Username: "testuser", Password: "testpass", Domain: "CORP", MaxSizeBytes: 1024 * 1024, PoolSize: 5, }, expectError: false, }, { name: "missing host", config: Config{ Share: "gohoarder", Username: "testuser", Password: "testpass", }, expectError: true, errorMsg: "host is required", }, { name: "missing share", config: Config{ Host: "fileserver.example.com", Username: "testuser", Password: "testpass", }, expectError: true, errorMsg: "share is required", }, { name: "default port", config: Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", }, expectError: false, }, { name: "default pool size", config: Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", }, expectError: false, }, } for _, tt := range tests { s.Run(tt.name, func() { storage, err := New(tt.config) if tt.expectError { s.Error(err) if tt.errorMsg != "" { s.Contains(err.Error(), tt.errorMsg) } s.Nil(storage) } else { // Note: This will fail in actual execution since we can't connect to a real SMB server // But it tests the validation logic if err != nil { // Connection errors are expected in unit tests s.Contains(err.Error(), "Failed to create initial SMB connection") } } }) } } func (s *SMBStorageTestSuite) TestKeyToPath() { tests := []struct { name string basePath string key string expectedWin string // Expected Windows-style path }{ { name: "simple key with base path", basePath: "packages", key: "test/file.txt", expectedWin: "packages\\test\\file.txt", }, { name: "simple key without base path", basePath: "", key: "test/file.txt", expectedWin: "test\\file.txt", }, { name: "nested key", basePath: "cache", key: "deep/nested/path/file.txt", expectedWin: "cache\\deep\\nested\\path\\file.txt", }, { name: "key with backslashes", basePath: "packages", key: "test\\file.txt", expectedWin: "packages\\test\\file.txt", }, } for _, tt := range tests { s.Run(tt.name, func() { storage := &SMBStorage{ config: Config{ Path: tt.basePath, }, } result := storage.keyToPath(tt.key) s.Equal(tt.expectedWin, result) }) } } func (s *SMBStorageTestSuite) TestPathToKey() { tests := []struct { name string basePath string path string expected string }{ { name: "windows path with base path", basePath: "packages", path: "packages\\test\\file.txt", expected: "test/file.txt", }, { name: "windows path without base path", basePath: "", path: "test\\file.txt", expected: "test/file.txt", }, { name: "nested windows path", basePath: "cache", path: "cache\\deep\\nested\\path\\file.txt", expected: "deep/nested/path/file.txt", }, } for _, tt := range tests { s.Run(tt.name, func() { storage := &SMBStorage{ config: Config{ Path: tt.basePath, }, } result := storage.pathToKey(tt.path) s.Equal(tt.expected, result) }) } } func (s *SMBStorageTestSuite) TestConfigDefaults() { config := Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", } // This will fail to connect, but we can verify the config validation _, err := New(config) // We expect a connection error, not a validation error if err != nil { s.NotContains(err.Error(), "host is required") s.NotContains(err.Error(), "share is required") } } func (s *SMBStorageTestSuite) TestPathNormalization() { tests := []struct { name string inputPath string expectedPath string }{ { name: "path with trailing slash", inputPath: "packages/", expectedPath: "packages", }, { name: "path with trailing backslash", inputPath: "packages\\", expectedPath: "packages", }, { name: "path without trailing slash", inputPath: "packages", expectedPath: "packages", }, { name: "empty path", inputPath: "", expectedPath: "", }, { name: "nested path with trailing slash", inputPath: "cache/packages/", expectedPath: "cache/packages", }, } for _, tt := range tests { s.Run(tt.name, func() { config := Config{ Host: "fileserver.example.com", Share: "gohoarder", Path: tt.inputPath, Username: "testuser", Password: "testpass", } // This will fail to connect, but we can check the config storage, _ := New(config) if storage != nil { s.Equal(tt.expectedPath, storage.config.Path) } }) } } func (s *SMBStorageTestSuite) TestPoolSizeDefaults() { config := Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", } storage, _ := New(config) if storage != nil { s.Equal(5, storage.poolSize) // Default pool size } } func (s *SMBStorageTestSuite) TestPortDefaults() { config := Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", } storage, _ := New(config) if storage != nil { s.Equal(445, storage.config.Port) // Default SMB port } } func (s *SMBStorageTestSuite) TestClose() { // Create a storage instance (will fail to connect but that's ok) config := Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", } storage, _ := New(config) if storage != nil { // Close should not panic err := storage.Close() s.NoError(err) } } func (s *SMBStorageTestSuite) TestConnectionPoolChannel() { config := Config{ Host: "fileserver.example.com", Share: "gohoarder", Username: "testuser", Password: "testpass", PoolSize: 10, } storage, _ := New(config) if storage != nil { // Verify pool channel capacity s.NotNil(storage.connPool) s.Equal(10, cap(storage.connPool)) } } func (s *SMBStorageTestSuite) TestSMBConnectionStruct() { // Verify smbConnection structure exists and has required fields conn := &smbConnection{} s.NotNil(conn) }