diff options
35 files changed, 260 insertions, 233 deletions
diff --git a/cmd/mobius-hotline-server/main.go b/cmd/mobius-hotline-server/main.go index cc24f5f..659ad13 100644 --- a/cmd/mobius-hotline-server/main.go +++ b/cmd/mobius-hotline-server/main.go @@ -246,7 +246,7 @@ func copyDirRecursive(src, dst string) error { if err := os.MkdirAll(dstPath, 0755); err != nil { return fmt.Errorf("failed to create directory %s: %w", dstPath, err) } - + // Recursively copy subdirectory if err := copyDirRecursive(srcPath, dstPath); err != nil { return fmt.Errorf("failed to copy subdirectory %s: %w", srcPath, err) diff --git a/cmd/mobius-hotline-server/main_test.go b/cmd/mobius-hotline-server/main_test.go index dec2ebf..a527d8b 100644 --- a/cmd/mobius-hotline-server/main_test.go +++ b/cmd/mobius-hotline-server/main_test.go @@ -22,7 +22,7 @@ func TestCopyDir(t *testing.T) { expectedFiles := []string{ "config.yaml", "Agreement.txt", - "MessageBoard.txt", + "MessageBoard.txt", "ThreadedNews.yaml", "Users/admin.yaml", "Users/guest.yaml", @@ -32,7 +32,7 @@ func TestCopyDir(t *testing.T) { for _, expectedFile := range expectedFiles { fullPath := path.Join(dstDir, expectedFile) assert.FileExists(t, fullPath, "Expected file %s to exist", expectedFile) - + // Verify file is not empty info, err := os.Stat(fullPath) require.NoError(t, err) @@ -55,7 +55,7 @@ func TestCopyDir(t *testing.T) { func TestCopyDirNonexistentSource(t *testing.T) { dstDir := t.TempDir() - + err := copyDir("nonexistent/directory", dstDir) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to read source directory") @@ -71,7 +71,7 @@ func TestCopyDirRecursive(t *testing.T) { // Verify nested structure is copied correctly nestedPath := path.Join(dstDir, "Users", "admin.yaml") assert.FileExists(t, nestedPath) - + // Verify nested Files directory filesDir := path.Join(dstDir, "Files") info, err := os.Stat(filesDir) @@ -89,7 +89,7 @@ func TestCopyFile(t *testing.T) { // Verify file was copied correctly assert.FileExists(t, dstFile) - + // Verify file is not empty info, err := os.Stat(dstFile) require.NoError(t, err) @@ -121,7 +121,7 @@ func TestCopyDirPermissions(t *testing.T) { info, err := os.Stat(path.Join(dstDir, "Users")) require.NoError(t, err) assert.True(t, info.IsDir()) - + // Check that directory has reasonable permissions (at least readable/executable) mode := info.Mode() assert.True(t, mode&0400 != 0, "Directory should be readable") @@ -132,10 +132,10 @@ func TestFindConfigPath(t *testing.T) { // Test function behavior by checking it returns one of the expected paths or fallback t.Run("returns valid path", func(t *testing.T) { result := findConfigPath() - + // Should return either one of the search paths that exists, or "config" fallback validPaths := append([]string{"config"}, mobius.ConfigSearchOrder...) - + found := false for _, validPath := range validPaths { if result == validPath { @@ -143,16 +143,16 @@ func TestFindConfigPath(t *testing.T) { break } } - + assert.True(t, found, "findConfigPath should return one of the valid paths or fallback, got: %s", result) }) - - // Test directory vs file validation + + // Test directory vs file validation t.Run("validates directory vs file", func(t *testing.T) { // This test verifies the function logic but can't control system directories // The function correctly validates that only directories are returned result := findConfigPath() - + // Verify result is an actual directory if it exists if result != "config" { info, err := os.Stat(result) @@ -160,22 +160,22 @@ func TestFindConfigPath(t *testing.T) { assert.True(t, info.IsDir(), "Returned path should be a directory") } }) - + // Test with existing directory t.Run("finds existing directory", func(t *testing.T) { tmpDir := t.TempDir() originalDir, err := os.Getwd() require.NoError(t, err) defer func() { _ = os.Chdir(originalDir) }() - + err = os.Chdir(tmpDir) require.NoError(t, err) - + // Create a config directory err = os.Mkdir("config", 0755) require.NoError(t, err) - + result := findConfigPath() assert.Equal(t, "config", result) }) -}
\ No newline at end of file +} diff --git a/hotline/access_test.go b/hotline/access_test.go index fa2f6f6..2c5b8f4 100644 --- a/hotline/access_test.go +++ b/hotline/access_test.go @@ -1,11 +1,12 @@ package hotline import ( + "strings" + "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" - "strings" - "testing" ) func Test_accessBitmap_IsSet(t *testing.T) { diff --git a/hotline/account.go b/hotline/account.go index 39ea974..37fb956 100644 --- a/hotline/account.go +++ b/hotline/account.go @@ -3,9 +3,10 @@ package hotline import ( "encoding/binary" "fmt" - "golang.org/x/crypto/bcrypt" "io" "slices" + + "golang.org/x/crypto/bcrypt" ) const GuestAccount = "guest" // default account used when no login is provided for a connection diff --git a/hotline/chat.go b/hotline/chat.go index dcde1d3..f35fac5 100644 --- a/hotline/chat.go +++ b/hotline/chat.go @@ -2,9 +2,10 @@ package hotline import ( "crypto/rand" - "github.com/stretchr/testify/mock" "slices" "sync" + + "github.com/stretchr/testify/mock" ) type PrivateChat struct { diff --git a/hotline/chat_test.go b/hotline/chat_test.go index 0bacc09..e08a81b 100644 --- a/hotline/chat_test.go +++ b/hotline/chat_test.go @@ -1,8 +1,9 @@ package hotline import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestMemChatManager(t *testing.T) { diff --git a/hotline/client_conn.go b/hotline/client_conn.go index d324591..a203630 100644 --- a/hotline/client_conn.go +++ b/hotline/client_conn.go @@ -4,11 +4,12 @@ import ( "cmp" "encoding/binary" "fmt" - "golang.org/x/crypto/bcrypt" "io" "log/slog" "strings" "sync" + + "golang.org/x/crypto/bcrypt" ) var clientConnSortFunc = func(a, b *ClientConn) int { diff --git a/hotline/client_conn_test.go b/hotline/client_conn_test.go index 9f04d66..e5acf82 100644 --- a/hotline/client_conn_test.go +++ b/hotline/client_conn_test.go @@ -1,2 +1 @@ package hotline - diff --git a/hotline/client_manager.go b/hotline/client_manager.go index ab6372c..22d096d 100644 --- a/hotline/client_manager.go +++ b/hotline/client_manager.go @@ -3,10 +3,11 @@ package hotline import ( "cmp" "encoding/binary" - "github.com/stretchr/testify/mock" "slices" "sync" "sync/atomic" + + "github.com/stretchr/testify/mock" ) type ClientID [2]byte diff --git a/hotline/config.go b/hotline/config.go index 75d5c4d..d918ecb 100644 --- a/hotline/config.go +++ b/hotline/config.go @@ -1,18 +1,18 @@ package hotline type Config struct { - Name string `yaml:"Name" validate:"required,max=50"` // Name used for Tracker registration - Description string `yaml:"Description" validate:"required,max=200"` // Description used for Tracker registration + Name string `yaml:"Name" validate:"required,max=50"` // Name used for Tracker registration + Description string `yaml:"Description" validate:"required,max=200"` // Description used for Tracker registration BannerFile string `yaml:"BannerFile" validate:"omitempty,bannerext"` // Path to Banner jpg or gif - FileRoot string `yaml:"FileRoot" validate:"required"` // Path to Files - EnableTrackerRegistration bool `yaml:"EnableTrackerRegistration"` // Toggle Tracker Registration - Trackers []string `yaml:"Trackers" validate:"dive,hostname_port"` // List of trackers that the server should register with - NewsDelimiter string `yaml:"NewsDelimiter"` // String used to separate news posts - NewsDateFormat string `yaml:"NewsDateFormat"` // Go template string to customize news date format - MaxDownloads int `yaml:"MaxDownloads"` // Global simultaneous download limit - MaxDownloadsPerClient int `yaml:"MaxDownloadsPerClient"` // Per client simultaneous download limit - MaxConnectionsPerIP int `yaml:"MaxConnectionsPerIP"` // Max connections per IP - PreserveResourceForks bool `yaml:"PreserveResourceForks"` // Enable preservation of file info and resource forks in sidecar files - IgnoreFiles []string `yaml:"IgnoreFiles"` // List of regular expression for filtering files from the file list - EnableBonjour bool `yaml:"EnableBonjour"` // Enable service announcement on local network with Bonjour + FileRoot string `yaml:"FileRoot" validate:"required"` // Path to Files + EnableTrackerRegistration bool `yaml:"EnableTrackerRegistration"` // Toggle Tracker Registration + Trackers []string `yaml:"Trackers" validate:"dive,hostname_port"` // List of trackers that the server should register with + NewsDelimiter string `yaml:"NewsDelimiter"` // String used to separate news posts + NewsDateFormat string `yaml:"NewsDateFormat"` // Go template string to customize news date format + MaxDownloads int `yaml:"MaxDownloads"` // Global simultaneous download limit + MaxDownloadsPerClient int `yaml:"MaxDownloadsPerClient"` // Per client simultaneous download limit + MaxConnectionsPerIP int `yaml:"MaxConnectionsPerIP"` // Max connections per IP + PreserveResourceForks bool `yaml:"PreserveResourceForks"` // Enable preservation of file info and resource forks in sidecar files + IgnoreFiles []string `yaml:"IgnoreFiles"` // List of regular expression for filtering files from the file list + EnableBonjour bool `yaml:"EnableBonjour"` // Enable service announcement on local network with Bonjour } diff --git a/hotline/field_test.go b/hotline/field_test.go index 3440b0d..6dff102 100644 --- a/hotline/field_test.go +++ b/hotline/field_test.go @@ -2,8 +2,9 @@ package hotline import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestHello(t *testing.T) { diff --git a/hotline/file_name_with_info_test.go b/hotline/file_name_with_info_test.go index 5095acf..be9addf 100644 --- a/hotline/file_name_with_info_test.go +++ b/hotline/file_name_with_info_test.go @@ -1,9 +1,10 @@ package hotline import ( - "github.com/stretchr/testify/assert" "io" "testing" + + "github.com/stretchr/testify/assert" ) func TestFileNameWithInfo_MarshalBinary(t *testing.T) { diff --git a/hotline/file_path_test.go b/hotline/file_path_test.go index 23c9a96..ee0cbac 100644 --- a/hotline/file_path_test.go +++ b/hotline/file_path_test.go @@ -2,8 +2,9 @@ package hotline import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestFilePath_Write(t *testing.T) { diff --git a/hotline/file_store.go b/hotline/file_store.go index 1525e2e..8c18256 100644 --- a/hotline/file_store.go +++ b/hotline/file_store.go @@ -1,10 +1,11 @@ package hotline import ( - "github.com/stretchr/testify/mock" "io/fs" "os" "time" + + "github.com/stretchr/testify/mock" ) type FileStore interface { diff --git a/hotline/file_transfer_test.go b/hotline/file_transfer_test.go index ba29910..a5c4afe 100644 --- a/hotline/file_transfer_test.go +++ b/hotline/file_transfer_test.go @@ -2,9 +2,10 @@ package hotline import ( "encoding/binary" - "github.com/stretchr/testify/assert" "io" "testing" + + "github.com/stretchr/testify/assert" ) func TestFileTransfer_String(t *testing.T) { @@ -178,10 +179,10 @@ func TestFileHeader_Payload(t *testing.T) { func Test_folderUpload_FormattedPath(t *testing.T) { tests := []struct { - name string - pathItemCount [2]byte - fileNamePath []byte - want string + name string + pathItemCount [2]byte + fileNamePath []byte + want string }{ { name: "empty path", @@ -210,7 +211,7 @@ func Test_folderUpload_FormattedPath(t *testing.T) { 0x04, // segment length 0x75, 0x73, 0x65, 0x72, // "user" 0x00, 0x00, // path separator - 0x09, // segment length + 0x09, // segment length 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, // "documents" }, want: "home/user/documents", @@ -220,10 +221,10 @@ func Test_folderUpload_FormattedPath(t *testing.T) { pathItemCount: [2]byte{0x00, 0x02}, fileNamePath: []byte{ 0x00, 0x00, // path separator - 0x07, // segment length + 0x07, // segment length 0x4d, 0x79, 0x20, 0x46, 0x69, 0x6c, 0x65, // "My File" 0x00, 0x00, // path separator - 0x0d, // segment length (13 bytes) + 0x0d, // segment length (13 bytes) 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6e, 0x74, 0x2e, 0x74, 0x78, 0x74, // "Important.txt" }, want: "My File/Important.txt", @@ -239,8 +240,8 @@ func Test_folderUpload_FormattedPath(t *testing.T) { 0x01, // segment length 0x62, // "b" 0x00, 0x00, // path separator - 0x01, // segment length - 0x63, // "c" + 0x01, // segment length + 0x63, // "c" }, want: "a/b/c", }, @@ -249,7 +250,7 @@ func Test_folderUpload_FormattedPath(t *testing.T) { pathItemCount: [2]byte{0x00, 0x01}, fileNamePath: []byte{ 0x00, 0x00, // path separator - 0x08, // segment length + 0x08, // segment length 0x74, 0x65, 0x73, 0x74, 0x40, 0x24, 0x25, 0x26, // "test@$%&" }, want: "test@$%&", diff --git a/hotline/files_test.go b/hotline/files_test.go index 9bed670..3070313 100644 --- a/hotline/files_test.go +++ b/hotline/files_test.go @@ -3,10 +3,11 @@ package hotline import ( "bytes" "encoding/binary" - "github.com/stretchr/testify/assert" "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" ) func TestEncodeFilePath(t *testing.T) { diff --git a/hotline/flattened_file_object.go b/hotline/flattened_file_object.go index 7c0cd7d..0300c71 100644 --- a/hotline/flattened_file_object.go +++ b/hotline/flattened_file_object.go @@ -45,7 +45,7 @@ type FlatFileInformationFork struct { func NewFlatFileInformationFork(fileName string, modifyTime [8]byte, typeSignature string, creatorSignature string) FlatFileInformationFork { return FlatFileInformationFork{ - Platform: PlatformAMAC, // TODO: Remove hardcode to support "MWIN" Platform (maybe?) + Platform: PlatformAMAC, // TODO: Remove hardcode to support "MWIN" Platform (maybe?) TypeSignature: [4]byte([]byte(typeSignature)), // TODO: Don't infer types from filename CreatorSignature: [4]byte([]byte(creatorSignature)), // TODO: Don't infer types from filename PlatformFlags: [4]byte{0, 0, 1, 0}, // TODO: What is this? diff --git a/hotline/flattened_file_object_test.go b/hotline/flattened_file_object_test.go index 274ca2b..c34af8a 100644 --- a/hotline/flattened_file_object_test.go +++ b/hotline/flattened_file_object_test.go @@ -2,8 +2,9 @@ package hotline import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestFlatFileInformationFork_UnmarshalBinary(t *testing.T) { diff --git a/hotline/news_test.go b/hotline/news_test.go index 2af3cd2..80676f1 100644 --- a/hotline/news_test.go +++ b/hotline/news_test.go @@ -1,9 +1,10 @@ package hotline import ( - "github.com/stretchr/testify/assert" "io" "testing" + + "github.com/stretchr/testify/assert" ) func TestNewsCategoryListData15_MarshalBinary(t *testing.T) { @@ -289,8 +290,8 @@ func TestNewsArtListData_Write(t *testing.T) { 0x00, 0x00, 0x00, 0x05, // Count: 5 0x04, // Name length: 4 0x74, 0x65, 0x73, 0x74, // Name: "test" - 0x04, // Description length: 4 - 0x64, 0x65, 0x73, 0x63, // Description: "desc" + 0x04, // Description length: 4 + 0x64, 0x65, 0x73, 0x63, // Description: "desc" }, wantID: [4]byte{0x00, 0x01, 0x02, 0x03}, wantCount: 5, @@ -307,9 +308,9 @@ func TestNewsArtListData_Write(t *testing.T) { 0x00, 0x00, 0x00, 0x01, // Count: 1 0x04, // Name length: 4 0x74, 0x65, 0x73, 0x74, // Name: "test" - 0x04, // Description length: 4 - 0x64, 0x65, 0x73, 0x63, // Description: "desc" - 0xAA, 0xBB, 0xCC, // NewsArtList data + 0x04, // Description length: 4 + 0x64, 0x65, 0x73, 0x63, // Description: "desc" + 0xAA, 0xBB, 0xCC, // NewsArtList data }, wantID: [4]byte{0x00, 0x01, 0x02, 0x03}, wantCount: 1, @@ -340,9 +341,9 @@ func TestNewsArtListData_Write(t *testing.T) { input: []byte{ 0x00, 0x00, 0x00, 0x00, // ID 0x00, 0x00, 0x00, 0x0A, // Count: 10 - 0x0A, // Name length: 10 + 0x0A, // Name length: 10 0x4C, 0x6F, 0x6E, 0x67, 0x65, 0x72, 0x4E, 0x61, 0x6D, 0x65, // Name: "LongerName" - 0x0B, // Description length: 11 + 0x0B, // Description length: 11 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, // Description: "Description" }, wantID: [4]byte{0x00, 0x00, 0x00, 0x00}, @@ -405,8 +406,8 @@ func TestNewsArtListData_Write_PartialData(t *testing.T) { { name: "split across ID boundary", chunks: [][]byte{ - {0x00, 0x01}, // First 2 bytes of ID - {0x02, 0x03}, // Last 2 bytes of ID + {0x00, 0x01}, // First 2 bytes of ID + {0x02, 0x03}, // Last 2 bytes of ID {0x00, 0x00, 0x00, 0x02}, // Count: 2 {0x03}, // Name length: 3 {0x66, 0x6f, 0x6f}, // Name: "foo" @@ -425,10 +426,10 @@ func TestNewsArtListData_Write_PartialData(t *testing.T) { chunks: [][]byte{ {0x00, 0x00, 0x00, 0x00}, // ID {0x00, 0x00, 0x00, 0x01}, // Count: 1 - {0x05}, // Name length: 5 - {0x68, 0x65}, // "he" - {0x6c, 0x6c, 0x6f}, // "llo" - {0x00}, // Description length: 0 + {0x05}, // Name length: 5 + {0x68, 0x65}, // "he" + {0x6c, 0x6c, 0x6f}, // "llo" + {0x00}, // Description length: 0 }, wantID: [4]byte{0x00, 0x00, 0x00, 0x00}, wantCount: 1, @@ -442,10 +443,10 @@ func TestNewsArtListData_Write_PartialData(t *testing.T) { chunks: [][]byte{ {0xAA, 0xBB, 0xCC, 0xDD}, // ID {0x00, 0x00, 0x00, 0x05}, // Count: 5 - {0x01, 0x41}, // Name length: 1, Name: "A" - {0x01, 0x42}, // Description length: 1, Description: "B" - {0x11, 0x22}, // Article list part 1 - {0x33, 0x44, 0x55}, // Article list part 2 + {0x01, 0x41}, // Name length: 1, Name: "A" + {0x01, 0x42}, // Description length: 1, Description: "B" + {0x11, 0x22}, // Article list part 1 + {0x33, 0x44, 0x55}, // Article list part 2 }, wantID: [4]byte{0xAA, 0xBB, 0xCC, 0xDD}, wantCount: 5, @@ -459,7 +460,7 @@ func TestNewsArtListData_Write_PartialData(t *testing.T) { chunks: [][]byte{ {0x01}, {0x02}, {0x03}, {0x04}, // ID {0x00}, {0x00}, {0x00}, {0x00}, // Count: 0 - {0x02}, // Name length: 2 + {0x02}, // Name length: 2 {0x41}, {0x42}, // Name: "AB" {0x00}, // Description length: 0 }, @@ -684,8 +685,8 @@ func TestNewsCategoryListData15_Write(t *testing.T) { input: []byte{ 0x00, 0x02, // Type: Bundle 0x00, 0x01, // Count: 1 - 0x03, // Name length: 3 - 0x66, 0x6f, 0x6f, // Name: "foo" + 0x03, // Name length: 3 + 0x66, 0x6f, 0x6f, // Name: "foo" }, wantType: [2]byte{0x00, 0x02}, wantName: "foo", @@ -727,7 +728,7 @@ func TestNewsCategoryListData15_Write(t *testing.T) { input: []byte{ 0x00, 0x02, // Type: Bundle 0x00, 0x05, // Count: 5 - 0x0a, // Name length: 10 + 0x0a, // Name length: 10 0x4c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, // Name: "LongerName" }, wantType: [2]byte{0x00, 0x02}, @@ -758,9 +759,9 @@ func TestNewsCategoryListData15_Write(t *testing.T) { func TestNewsCategoryListData15_WriteRead_RoundTrip(t *testing.T) { tests := []struct { - name string - newscat NewsCategoryListData15 - wantErr bool + name string + newscat NewsCategoryListData15 + wantErr bool }{ { name: "bundle round trip", @@ -844,11 +845,11 @@ func TestNewsCategoryListData15_Write_PartialData(t *testing.T) { { name: "split across type boundary", chunks: [][]byte{ - {0x00}, // First byte of type - {0x02}, // Second byte of type - {0x00, 0x01}, // Count - {0x03}, // Name length - {0x66, 0x6f, 0x6f}, // Name: "foo" + {0x00}, // First byte of type + {0x02}, // Second byte of type + {0x00, 0x01}, // Count + {0x03}, // Name length + {0x66, 0x6f, 0x6f}, // Name: "foo" }, wantType: [2]byte{0x00, 0x02}, wantName: "foo", diff --git a/hotline/server_blackbox_test.go b/hotline/server_blackbox_test.go index 888ca3f..7033703 100644 --- a/hotline/server_blackbox_test.go +++ b/hotline/server_blackbox_test.go @@ -4,11 +4,12 @@ import ( "cmp" "encoding/binary" "encoding/hex" - "github.com/stretchr/testify/assert" "log/slog" "os" "slices" "testing" + + "github.com/stretchr/testify/assert" ) func NewTestLogger() *slog.Logger { diff --git a/hotline/server_test.go b/hotline/server_test.go index 574aae7..db70480 100644 --- a/hotline/server_test.go +++ b/hotline/server_test.go @@ -5,13 +5,14 @@ import ( "context" "encoding/binary" "fmt" - "github.com/stretchr/testify/assert" "io" "log/slog" "os" "strings" "testing" "time" + + "github.com/stretchr/testify/assert" ) type mockReadWriter struct { @@ -400,20 +401,20 @@ func TestServer_registerWithTrackers(t *testing.T) { func TestServer_registerWithTrackers_ContextCancellation(t *testing.T) { tests := []struct { - name string - cancelAfter time.Duration - expectedCalls int // Number of expected registration calls before cancellation - trackerCount int + name string + cancelAfter time.Duration + expectedCalls int // Number of expected registration calls before cancellation + trackerCount int }{ { - name: "immediate cancellation", - cancelAfter: 10 * time.Millisecond, + name: "immediate cancellation", + cancelAfter: 10 * time.Millisecond, expectedCalls: 2, // Should complete immediate registration trackerCount: 2, }, { - name: "cancellation after first ticker", - cancelAfter: 100 * time.Millisecond, + name: "cancellation after first ticker", + cancelAfter: 100 * time.Millisecond, expectedCalls: 2, // Should only do immediate registration within 100ms trackerCount: 2, }, @@ -470,10 +471,10 @@ func TestServer_registerWithTrackers_ContextCancellation(t *testing.T) { func TestServer_registerWithTrackers_PeriodicRegistration(t *testing.T) { t.Skip("Skipping timing-sensitive test - would take 5+ minutes to run reliably") - + // This test would verify that periodic re-registration happens every trackerUpdateFrequency seconds // but it's impractical to run in normal test suites due to the 300-second interval - + mockRegistrar := &MockTrackerRegistrar{} config := Config{ EnableTrackerRegistration: true, diff --git a/hotline/stats_test.go b/hotline/stats_test.go index 2174227..d853dee 100644 --- a/hotline/stats_test.go +++ b/hotline/stats_test.go @@ -1,9 +1,10 @@ package hotline import ( - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestStats_Increment(t *testing.T) { @@ -51,13 +52,13 @@ func TestStats_Increment(t *testing.T) { func TestStats_Increment_Multiple_Calls(t *testing.T) { stats := NewStats() - + stats.Increment(StatCurrentlyConnected) assert.Equal(t, 1, stats.Get(StatCurrentlyConnected)) - + stats.Increment(StatCurrentlyConnected) assert.Equal(t, 2, stats.Get(StatCurrentlyConnected)) - + stats.Increment(StatCurrentlyConnected, StatDownloadCounter) assert.Equal(t, 3, stats.Get(StatCurrentlyConnected)) assert.Equal(t, 1, stats.Get(StatDownloadCounter)) @@ -65,28 +66,28 @@ func TestStats_Increment_Multiple_Calls(t *testing.T) { func TestStats_Decrement(t *testing.T) { tests := []struct { - name string - setupValue int - key int - expected int + name string + setupValue int + key int + expected int }{ { - name: "decrement from positive value", - setupValue: 5, - key: StatCurrentlyConnected, - expected: 4, + name: "decrement from positive value", + setupValue: 5, + key: StatCurrentlyConnected, + expected: 4, }, { - name: "decrement from zero stays zero", - setupValue: 0, - key: StatCurrentlyConnected, - expected: 0, + name: "decrement from zero stays zero", + setupValue: 0, + key: StatCurrentlyConnected, + expected: 0, }, { - name: "decrement from one", - setupValue: 1, - key: StatCurrentlyConnected, - expected: 0, + name: "decrement from one", + setupValue: 1, + key: StatCurrentlyConnected, + expected: 0, }, } @@ -94,9 +95,9 @@ func TestStats_Decrement(t *testing.T) { t.Run(tt.name, func(t *testing.T) { stats := NewStats() stats.Set(tt.key, tt.setupValue) - + stats.Decrement(tt.key) - + assert.Equal(t, tt.expected, stats.Get(tt.key)) }) } @@ -104,13 +105,13 @@ func TestStats_Decrement(t *testing.T) { func TestStats_Decrement_Multiple_Calls(t *testing.T) { stats := NewStats() - + stats.Set(StatCurrentlyConnected, 10) assert.Equal(t, 10, stats.Get(StatCurrentlyConnected)) - + stats.Decrement(StatCurrentlyConnected) assert.Equal(t, 9, stats.Get(StatCurrentlyConnected)) - + stats.Decrement(StatCurrentlyConnected) assert.Equal(t, 8, stats.Get(StatCurrentlyConnected)) } @@ -151,13 +152,13 @@ func TestStats_Set(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stats := NewStats() - + if tt.name == "overwrite existing value" { stats.Set(tt.key, 50) } - + stats.Set(tt.key, tt.value) - + assert.Equal(t, tt.expected, stats.Get(tt.key)) }) } @@ -193,13 +194,13 @@ func TestStats_Get(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stats := NewStats() - + if tt.name == "get after increment" { stats.Increment(tt.key) } else { stats.Set(tt.key, tt.setValue) } - + result := stats.Get(tt.key) assert.Equal(t, tt.expected, result) }) @@ -208,7 +209,7 @@ func TestStats_Get(t *testing.T) { func TestStats_Get_Default_Values(t *testing.T) { stats := NewStats() - + expectedDefaults := map[int]int{ StatCurrentlyConnected: 0, StatDownloadsInProgress: 0, @@ -219,7 +220,7 @@ func TestStats_Get_Default_Values(t *testing.T) { StatUploadCounter: 0, StatConnectionCounter: 0, } - + for key, expected := range expectedDefaults { assert.Equal(t, expected, stats.Get(key)) } @@ -227,10 +228,10 @@ func TestStats_Get_Default_Values(t *testing.T) { func TestStats_Values(t *testing.T) { stats := NewStats() - + // Test default values values := stats.Values() - + assert.Equal(t, 0, values["CurrentlyConnected"]) assert.Equal(t, 0, values["DownloadsInProgress"]) assert.Equal(t, 0, values["UploadsInProgress"]) @@ -240,7 +241,7 @@ func TestStats_Values(t *testing.T) { assert.Equal(t, 0, values["DownloadCounter"]) assert.Equal(t, 0, values["UploadCounter"]) assert.NotNil(t, values["Since"]) - + // Verify Since is a time.Time _, ok := values["Since"].(time.Time) assert.True(t, ok, "Since should be a time.Time") @@ -248,15 +249,15 @@ func TestStats_Values(t *testing.T) { func TestStats_Values_WithModifiedStats(t *testing.T) { stats := NewStats() - + // Modify some stats stats.Set(StatCurrentlyConnected, 10) stats.Set(StatDownloadsInProgress, 5) stats.Increment(StatConnectionCounter) stats.Increment(StatDownloadCounter, StatUploadCounter) - + values := stats.Values() - + assert.Equal(t, 10, values["CurrentlyConnected"]) assert.Equal(t, 5, values["DownloadsInProgress"]) assert.Equal(t, 0, values["UploadsInProgress"]) @@ -270,7 +271,7 @@ func TestStats_Values_WithModifiedStats(t *testing.T) { func TestStats_Values_ContainsAllKeys(t *testing.T) { stats := NewStats() values := stats.Values() - + expectedKeys := []string{ "CurrentlyConnected", "DownloadsInProgress", @@ -282,12 +283,12 @@ func TestStats_Values_ContainsAllKeys(t *testing.T) { "UploadCounter", "Since", } - + for _, key := range expectedKeys { _, exists := values[key] assert.True(t, exists, "Key %s should exist in Values() output", key) } - + // Should have exactly 9 keys assert.Equal(t, 9, len(values)) -}
\ No newline at end of file +} diff --git a/hotline/transaction_test.go b/hotline/transaction_test.go index 97d865d..44afa6c 100644 --- a/hotline/transaction_test.go +++ b/hotline/transaction_test.go @@ -2,8 +2,9 @@ package hotline import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func Test_transactionScanner(t *testing.T) { diff --git a/hotline/transfer_test.go b/hotline/transfer_test.go index 9155ad7..94a14b6 100644 --- a/hotline/transfer_test.go +++ b/hotline/transfer_test.go @@ -3,9 +3,10 @@ package hotline import ( "bytes" "fmt" - "github.com/stretchr/testify/assert" "io" "testing" + + "github.com/stretchr/testify/assert" ) func TestTransfer_Write(t *testing.T) { diff --git a/hotline/user_test.go b/hotline/user_test.go index 2429009..22def00 100644 --- a/hotline/user_test.go +++ b/hotline/user_test.go @@ -2,8 +2,9 @@ package hotline import ( "bytes" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestReadUser(t *testing.T) { diff --git a/internal/mobius/account_manager.go b/internal/mobius/account_manager.go index d9169c9..1265d9c 100644 --- a/internal/mobius/account_manager.go +++ b/internal/mobius/account_manager.go @@ -2,14 +2,15 @@ package mobius import ( "fmt" - "github.com/jhalter/mobius/hotline" - "github.com/stretchr/testify/mock" - "gopkg.in/yaml.v3" "os" "path" "path/filepath" "strings" "sync" + + "github.com/jhalter/mobius/hotline" + "github.com/stretchr/testify/mock" + "gopkg.in/yaml.v3" ) // loadFromYAMLFile loads data from a YAML file into the provided data structure. diff --git a/internal/mobius/account_manager_test.go b/internal/mobius/account_manager_test.go index b0bfd79..daf7364 100644 --- a/internal/mobius/account_manager_test.go +++ b/internal/mobius/account_manager_test.go @@ -1,12 +1,13 @@ package mobius import ( - "github.com/jhalter/mobius/hotline" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "os" "path" "testing" + + "github.com/jhalter/mobius/hotline" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // copyTestFiles copies test config files to a temporary directory diff --git a/internal/mobius/ban.go b/internal/mobius/ban.go index b4fde95..dcb592e 100644 --- a/internal/mobius/ban.go +++ b/internal/mobius/ban.go @@ -2,11 +2,12 @@ package mobius import ( "fmt" - "gopkg.in/yaml.v3" "os" "path" "sync" "time" + + "gopkg.in/yaml.v3" ) type BanFile struct { diff --git a/internal/mobius/ban_test.go b/internal/mobius/ban_test.go index 9f1f5d8..beef715 100644 --- a/internal/mobius/ban_test.go +++ b/internal/mobius/ban_test.go @@ -2,12 +2,13 @@ package mobius import ( "fmt" - "github.com/stretchr/testify/assert" "os" "path" "sync" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestNewBanFile(t *testing.T) { diff --git a/internal/mobius/config.go b/internal/mobius/config.go index c798e54..6e5fb9f 100644 --- a/internal/mobius/config.go +++ b/internal/mobius/config.go @@ -2,12 +2,13 @@ package mobius import ( "fmt" - "github.com/go-playground/validator/v10" - "github.com/jhalter/mobius/hotline" - "gopkg.in/yaml.v3" "os" "path/filepath" "strings" + + "github.com/go-playground/validator/v10" + "github.com/jhalter/mobius/hotline" + "gopkg.in/yaml.v3" ) var ConfigSearchOrder = []string{ diff --git a/internal/mobius/logger.go b/internal/mobius/logger.go index 909e6ab..60d4f0d 100644 --- a/internal/mobius/logger.go +++ b/internal/mobius/logger.go @@ -1,11 +1,12 @@ package mobius import ( - "gopkg.in/natefinch/lumberjack.v2" "io" "log/slog" "os" "time" + + "gopkg.in/natefinch/lumberjack.v2" ) const ( diff --git a/internal/mobius/news_test.go b/internal/mobius/news_test.go index b5d5ccd..753956e 100644 --- a/internal/mobius/news_test.go +++ b/internal/mobius/news_test.go @@ -12,11 +12,11 @@ import ( func TestNewFlatNews(t *testing.T) { tests := []struct { - name string - setupFile func(string) error - filePath string - wantErr bool - wantErrMsg string + name string + setupFile func(string) error + filePath string + wantErr bool + wantErrMsg string }{ { name: "valid file with content", @@ -35,11 +35,11 @@ func TestNewFlatNews(t *testing.T) { wantErr: false, }, { - name: "nonexistent file", - setupFile: func(path string) error { return nil }, - filePath: "nonexistent.txt", - wantErr: true, - wantErrMsg: "reload:", + name: "nonexistent file", + setupFile: func(path string) error { return nil }, + filePath: "nonexistent.txt", + wantErr: true, + wantErrMsg: "reload:", }, { name: "file with mixed line endings", @@ -55,13 +55,13 @@ func TestNewFlatNews(t *testing.T) { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() fullPath := filepath.Join(tempDir, tt.filePath) - + if err := tt.setupFile(fullPath); err != nil { t.Fatalf("Failed to setup test file: %v", err) } flatNews, err := NewFlatNews(fullPath) - + if tt.wantErr { if err == nil { t.Error("Expected error but got none") @@ -70,17 +70,17 @@ func TestNewFlatNews(t *testing.T) { } return } - + if err != nil { t.Errorf("Unexpected error: %v", err) return } - + if flatNews == nil { t.Error("Expected FlatNews instance but got nil") return } - + if flatNews.filePath != fullPath { t.Errorf("Expected filePath %q, got %q", fullPath, flatNews.filePath) } @@ -90,12 +90,12 @@ func TestNewFlatNews(t *testing.T) { func TestFlatNews_Reload(t *testing.T) { tests := []struct { - name string - initialData string - newData string - expectData string - wantErr bool - deleteFile bool + name string + initialData string + newData string + expectData string + wantErr bool + deleteFile bool }{ { name: "reload with new content", @@ -132,16 +132,16 @@ func TestFlatNews_Reload(t *testing.T) { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() filePath := filepath.Join(tempDir, "test.txt") - + if err := os.WriteFile(filePath, []byte(tt.initialData), 0644); err != nil { t.Fatalf("Failed to create initial file: %v", err) } - + flatNews, err := NewFlatNews(filePath) if err != nil { t.Fatalf("Failed to create FlatNews: %v", err) } - + if tt.deleteFile { if err := os.Remove(filePath); err != nil { t.Fatalf("Failed to delete file: %v", err) @@ -151,21 +151,21 @@ func TestFlatNews_Reload(t *testing.T) { t.Fatalf("Failed to write new data: %v", err) } } - + err = flatNews.Reload() - + if tt.wantErr { if err == nil { t.Error("Expected error but got none") } return } - + if err != nil { t.Errorf("Unexpected error: %v", err) return } - + if string(flatNews.data) != tt.expectData { t.Errorf("Expected data %q, got %q", tt.expectData, string(flatNews.data)) } @@ -175,9 +175,9 @@ func TestFlatNews_Reload(t *testing.T) { func TestFlatNews_Read(t *testing.T) { tests := []struct { - name string - fileContent string - bufferSize int + name string + fileContent string + bufferSize int expectedReads []readResult }{ { @@ -226,28 +226,28 @@ func TestFlatNews_Read(t *testing.T) { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() filePath := filepath.Join(tempDir, "test.txt") - + if err := os.WriteFile(filePath, []byte(tt.fileContent), 0644); err != nil { t.Fatalf("Failed to create test file: %v", err) } - + flatNews, err := NewFlatNews(filePath) if err != nil { t.Fatalf("Failed to create FlatNews: %v", err) } - + for i, expected := range tt.expectedReads { buf := make([]byte, tt.bufferSize) n, err := flatNews.Read(buf) - + if err != expected.err { t.Errorf("Read %d: expected error %v, got %v", i, expected.err, err) } - + if n != expected.n { t.Errorf("Read %d: expected n %d, got %d", i, expected.n, n) } - + actualData := string(buf[:n]) if actualData != expected.data { t.Errorf("Read %d: expected data %q, got %q", i, expected.data, actualData) @@ -299,44 +299,44 @@ func TestFlatNews_Write(t *testing.T) { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() filePath := filepath.Join(tempDir, "test.txt") - + if err := os.WriteFile(filePath, []byte(tt.initialData), 0644); err != nil { t.Fatalf("Failed to create initial file: %v", err) } - + flatNews, err := NewFlatNews(filePath) if err != nil { t.Fatalf("Failed to create FlatNews: %v", err) } - + n, err := flatNews.Write([]byte(tt.writeData)) - + if tt.wantErr { if err == nil { t.Error("Expected error but got none") } return } - + if err != nil { t.Errorf("Unexpected error: %v", err) return } - + if n != len(tt.writeData) { t.Errorf("Expected n %d, got %d", len(tt.writeData), n) } - + if string(flatNews.data) != tt.expectedData { t.Errorf("Expected data %q, got %q", tt.expectedData, string(flatNews.data)) } - + fileData, err := os.ReadFile(filePath) if err != nil { t.Errorf("Failed to read file: %v", err) return } - + if string(fileData) != tt.expectedData { t.Errorf("Expected file data %q, got %q", tt.expectedData, string(fileData)) } @@ -391,34 +391,34 @@ func TestFlatNews_Seek(t *testing.T) { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() filePath := filepath.Join(tempDir, "test.txt") - + if err := os.WriteFile(filePath, []byte(tt.fileContent), 0644); err != nil { t.Fatalf("Failed to create test file: %v", err) } - + flatNews, err := NewFlatNews(filePath) if err != nil { t.Fatalf("Failed to create FlatNews: %v", err) } - + offset, err := flatNews.Seek(tt.offset, tt.whence) - + if tt.expectErr { if err == nil { t.Error("Expected error but got none") } return } - + if err != nil { t.Errorf("Unexpected error: %v", err) return } - + if offset != tt.expectOffset { t.Errorf("Expected offset %d, got %d", tt.expectOffset, offset) } - + expectedReadOffset := int(tt.offset) if flatNews.readOffset != expectedReadOffset { t.Errorf("Expected readOffset %d, got %d", expectedReadOffset, flatNews.readOffset) @@ -430,24 +430,24 @@ func TestFlatNews_Seek(t *testing.T) { func TestFlatNews_ConcurrentOperations(t *testing.T) { tempDir := t.TempDir() filePath := filepath.Join(tempDir, "concurrent_test.txt") - + if err := os.WriteFile(filePath, []byte("initial content"), 0644); err != nil { t.Fatalf("Failed to create test file: %v", err) } - + flatNews, err := NewFlatNews(filePath) if err != nil { t.Fatalf("Failed to create FlatNews: %v", err) } - + var wg sync.WaitGroup errors := make(chan error, 10) - + for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() - + buf := make([]byte, 10) _, err := flatNews.Read(buf) if err != nil && err != io.EOF { @@ -455,33 +455,33 @@ func TestFlatNews_ConcurrentOperations(t *testing.T) { } }(i) } - + for i := 0; i < 3; i++ { wg.Add(1) go func(id int) { defer wg.Done() - + if err := flatNews.Reload(); err != nil { errors <- fmt.Errorf("reload goroutine %d: %w", id, err) } }(i) } - + for i := 0; i < 2; i++ { wg.Add(1) go func(id int) { defer wg.Done() - + data := fmt.Sprintf("data%d", id) if _, err := flatNews.Write([]byte(data)); err != nil { errors <- fmt.Errorf("write goroutine %d: %w", id, err) } }(i) } - + wg.Wait() close(errors) - + for err := range errors { t.Errorf("Concurrent operation error: %v", err) } @@ -494,7 +494,7 @@ type readResult struct { } func containsSubstring(s, substr string) bool { - return len(s) >= len(substr) && - (len(substr) == 0 || - strings.Contains(s, substr)) -}
\ No newline at end of file + return len(s) >= len(substr) && + (len(substr) == 0 || + strings.Contains(s, substr)) +} diff --git a/internal/mobius/threaded_news.go b/internal/mobius/threaded_news.go index c7daea4..f785bdf 100644 --- a/internal/mobius/threaded_news.go +++ b/internal/mobius/threaded_news.go @@ -4,12 +4,13 @@ import ( "cmp" "encoding/binary" "fmt" - "github.com/jhalter/mobius/hotline" - "gopkg.in/yaml.v3" "os" "slices" "sort" "sync" + + "github.com/jhalter/mobius/hotline" + "gopkg.in/yaml.v3" ) type ThreadedNewsYAML struct { diff --git a/internal/mobius/threaded_news_test.go b/internal/mobius/threaded_news_test.go index 2ff8a84..a44e834 100644 --- a/internal/mobius/threaded_news_test.go +++ b/internal/mobius/threaded_news_test.go @@ -2,12 +2,13 @@ package mobius import ( "fmt" - "github.com/jhalter/mobius/hotline" - "github.com/stretchr/testify/assert" "os" "path" "sync" "testing" + + "github.com/jhalter/mobius/hotline" + "github.com/stretchr/testify/assert" ) type TestData struct { diff --git a/internal/mobius/transaction_handlers_test.go b/internal/mobius/transaction_handlers_test.go index d943649..f4699e3 100644 --- a/internal/mobius/transaction_handlers_test.go +++ b/internal/mobius/transaction_handlers_test.go @@ -4,9 +4,6 @@ import ( "cmp" "encoding/binary" "errors" - "github.com/jhalter/mobius/hotline" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "io" "io/fs" "log/slog" @@ -16,6 +13,10 @@ import ( "strings" "testing" "time" + + "github.com/jhalter/mobius/hotline" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) type mockReadWriteSeeker struct { @@ -2895,8 +2896,7 @@ func TestHandleTranAgreed(t *testing.T) { }, ClientMgr: func() *hotline.MockClientMgr { m := hotline.MockClientMgr{} - m.On("List").Return([]*hotline.ClientConn{}, - ) + m.On("List").Return([]*hotline.ClientConn{}) return &m }(), }, |