From 0f9cf21f1c61a86810747fefb7492492ebae4d03 Mon Sep 17 00:00:00 2001 From: Marc Ole Bulling Date: Tue, 12 Dec 2023 18:55:26 +0100 Subject: [PATCH] Added tests and comments --- .../environment/flagparser/FlagParser_test.go | 255 ++++++++++++++++++ internal/models/Api.go | 19 ++ internal/storage/FileServing.go | 1 + .../processingstatus/ProcessingStatus_test.go | 66 +++++ 4 files changed, 341 insertions(+) create mode 100644 internal/environment/flagparser/FlagParser_test.go create mode 100644 internal/storage/processingstatus/ProcessingStatus_test.go diff --git a/internal/environment/flagparser/FlagParser_test.go b/internal/environment/flagparser/FlagParser_test.go new file mode 100644 index 00000000..d8b3b5b1 --- /dev/null +++ b/internal/environment/flagparser/FlagParser_test.go @@ -0,0 +1,255 @@ +package flagparser + +import ( + "bytes" + "flag" + "github.com/forceu/gokapi/internal/test" + "io" + "os" + "testing" +) + +func TestParseFlags(t *testing.T) { + DisableParsing = true + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + os.Args = append([]string{os.Args[0]}, "--version") + flags := ParseFlags() + test.IsEqualBool(t, flags.ShowVersion, false) + + DisableParsing = false + + tests := []struct { + name string + args []string + assertion func(flags MainFlags) + }{ + { + name: "ShowVersionFlagShort", + args: []string{"-v"}, + assertion: func(flags MainFlags) { + if !flags.ShowVersion { + t.Errorf("Expected ShowVersion to be true, got false") + } + }, + }, + { + name: "ShowVersionFlagLong", + args: []string{"--version"}, + assertion: func(flags MainFlags) { + if !flags.ShowVersion { + t.Errorf("Expected ShowVersion to be true, got false") + } + }, + }, + { + name: "ReconfigureFlag", + args: []string{"--reconfigure"}, + assertion: func(flags MainFlags) { + if !flags.Reconfigure { + t.Errorf("Expected Reconfigure to be true, got false") + } + }, + }, + { + name: "CreateSslFlagShort", + args: []string{"-create-ssl"}, + assertion: func(flags MainFlags) { + if !flags.CreateSsl { + t.Errorf("Expected CreateSsl to be true, got false") + } + }, + }, + { + name: "ConfigPathFlagShort", + args: []string{"-c", "/path/to/config"}, + assertion: func(flags MainFlags) { + if flags.ConfigPath != "/path/to/config" { + t.Errorf("Expected ConfigPath to be '/path/to/config', got '%s'", flags.ConfigPath) + } + }, + }, + { + name: "ConfigPathFlagLong", + args: []string{"--config", "/path/to/config"}, + assertion: func(flags MainFlags) { + if flags.ConfigPath != "/path/to/config" { + t.Errorf("Expected ConfigPath to be '/path/to/config', got '%s'", flags.ConfigPath) + } + }, + }, + { + name: "ConfigDirFlagShort", + args: []string{"-cd", "/path/to/config/dir"}, + assertion: func(flags MainFlags) { + if flags.ConfigDir != "/path/to/config/dir" { + t.Errorf("Expected ConfigDir to be '/path/to/config/dir', got '%s'", flags.ConfigDir) + } + }, + }, + { + name: "ConfigDirFlagLong", + args: []string{"--config-dir", "/path/to/config/dir"}, + assertion: func(flags MainFlags) { + if flags.ConfigDir != "/path/to/config/dir" { + t.Errorf("Expected ConfigDir to be '/path/to/config/dir', got '%s'", flags.ConfigDir) + } + }, + }, + { + name: "DataDirFlagShort", + args: []string{"-d", "/path/to/data"}, + assertion: func(flags MainFlags) { + if flags.DataDir != "/path/to/data" { + t.Errorf("Expected DataDir to be '/path/to/data', got '%s'", flags.DataDir) + } + }, + }, + { + name: "DataDirFlagLong", + args: []string{"--data", "/path/to/data"}, + assertion: func(flags MainFlags) { + if flags.DataDir != "/path/to/data" { + t.Errorf("Expected DataDir to be '/path/to/data', got '%s'", flags.DataDir) + } + }, + }, + { + name: "PortFlagShort", + args: []string{"-p", "8080"}, + assertion: func(flags MainFlags) { + if flags.Port != 8080 { + t.Errorf("Expected Port to be 8080, got %d", flags.Port) + } + }, + }, + { + name: "PortFlagLong", + args: []string{"--port", "9090"}, + assertion: func(flags MainFlags) { + if flags.Port != 9090 { + t.Errorf("Expected Port to be 9090, got %d", flags.Port) + } + }, + }, + { + name: "DisableCorsCheckFlag", + args: []string{"--disable-cors-check"}, + assertion: func(flags MainFlags) { + if !flags.DisableCorsCheck { + t.Errorf("Expected DisableCorsCheck to be true, got false") + } + }, + }, + } + + for _, testCase := range tests { + t.Run(testCase.name, func(t *testing.T) { + // Reset flags and arguments for each test + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + os.Args = append([]string{os.Args[0]}, testCase.args...) + + flags := ParseFlags() + testCase.assertion(flags) + }) + } +} + +func TestShowUsage(t *testing.T) { + aliases := []alias{ + {Long: "version", Short: "v"}, + {Long: "config", Short: "c"}, + {Long: "data", Short: "d"}, + } + + flagSet := flag.NewFlagSet("test", flag.ExitOnError) + flagSet.Bool("version", false, "Show version info") + flagSet.Bool("v", false, "alias") + flagSet.String("config", "", "Use provided config file") + flagSet.String("c", "", "alias") + flagSet.String("data", "", "Sets the data directory") + flagSet.String("d", "", "alias") + + capturedOutput := captureOutput(func() { + showUsage(*flagSet, aliases)() + }) + + expectedOutput := "Usage:\n\n" + + "-c, --config Use provided config file\n" + + "-d, --data Sets the data directory\n" + + "-v, --version Show version info\n" + + test.IsEqualString(t, capturedOutput, expectedOutput) +} +func TestIsAlias(t *testing.T) { + aliases := []alias{ + {Long: "version", Short: "v"}, + {Long: "config", Short: "c"}, + {Long: "data", Short: "d"}, + } + + testCases := []struct { + name string + input string + expect bool + }{ + {"IsAliasShortV", "v", true}, + {"IsAliasShortC", "c", true}, + {"IsAliasShortD", "d", true}, + {"IsAliasLong", "version", false}, + {"NotAlias", "other", false}, + {"NotAliasShort", "o", false}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := isAlias(tc.input, aliases) + test.IsEqualBool(t, result, tc.expect) + }) + } +} + +func TestHasAlias(t *testing.T) { + aliases := []alias{ + {Long: "version", Short: "v"}, + {Long: "config", Short: "c"}, + {Long: "data", Short: "d"}, + } + + testCases := []struct { + name string + input string + expect bool + expectVal string + }{ + {"HasAliasShort", "v", false, ""}, + {"HasAliasLong", "version", true, "v"}, + {"HasAliasLong", "config", true, "c"}, + {"HasAliasLong", "data", true, "d"}, + {"NotAlias", "other", false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, val := hasAlias(tc.input, aliases) + test.IsEqualBool(t, result, tc.expect) + test.IsEqualString(t, val, tc.expectVal) + }) + } +} + +// Helper function to capture output from a function +func captureOutput(f func()) string { + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + f() + + w.Close() + os.Stdout = old + + var capturedOutput bytes.Buffer + io.Copy(&capturedOutput, r) + + return capturedOutput.String() +} diff --git a/internal/models/Api.go b/internal/models/Api.go index 23556d02..67ae2a0b 100644 --- a/internal/models/Api.go +++ b/internal/models/Api.go @@ -1,15 +1,25 @@ package models const ( + // ApiPermView is the permission for viewing metadata of all uploaded files ApiPermView = 1 << iota + // ApiPermUpload is the permission for creating new files ApiPermUpload + // ApiPermDelete is the permission for deleting files ApiPermDelete + // ApiPermApiMod is the permission for adding / removing API key permissions ApiPermApiMod + // ApiPermEdit is the permission for editing parameters of uploaded files ApiPermEdit ) +// ApiPermNone means no permission granted const ApiPermNone = 0 + +// ApiPermAllNoApiMod means all permission granted, except ApiPermApiMod const ApiPermAllNoApiMod = 23 + +// ApiPermAll means all permission granted const ApiPermAll = 31 // ApiKey contains data of a single api key @@ -21,13 +31,17 @@ type ApiKey struct { Permissions uint8 `json:"Permissions"` } +// SetPermission grants one or more permissions func (key *ApiKey) SetPermission(permission uint8) { key.Permissions |= permission } + +// RemovePermission revokes one or more permissions func (key *ApiKey) RemovePermission(permission uint8) { key.Permissions &^= permission } +// HasPermission returns true if the key has the permission(s) func (key *ApiKey) HasPermission(permission uint8) bool { if permission == ApiPermNone { return true @@ -35,22 +49,27 @@ func (key *ApiKey) HasPermission(permission uint8) bool { return (key.Permissions & permission) == permission } +// HasPermissionView returns true if ApiPermView is granted func (key *ApiKey) HasPermissionView() bool { return key.HasPermission(ApiPermView) } +// HasPermissionUpload returns true if ApiPermUpload is granted func (key *ApiKey) HasPermissionUpload() bool { return key.HasPermission(ApiPermUpload) } +// HasPermissionDelete returns true if ApiPermDelete is granted func (key *ApiKey) HasPermissionDelete() bool { return key.HasPermission(ApiPermDelete) } +// HasPermissionApiMod returns true if ApiPermApiMod is granted func (key *ApiKey) HasPermissionApiMod() bool { return key.HasPermission(ApiPermApiMod) } +// HasPermissionEdit returns true if ApiPermEdit is granted func (key *ApiKey) HasPermissionEdit() bool { return key.HasPermission(ApiPermEdit) } diff --git a/internal/storage/FileServing.go b/internal/storage/FileServing.go index 70c6d3e3..932d02d3 100644 --- a/internal/storage/FileServing.go +++ b/internal/storage/FileServing.go @@ -264,6 +264,7 @@ func encryptChunkFile(file *os.File, metadata *models.File) (*os.File, error) { return tempFileEnc, nil } +// FormatTimestamp converts a timestamp to a string in the format YYYY-MM-DD HH:MM func FormatTimestamp(timestamp int64) string { return time.Unix(timestamp, 0).Format("2006-01-02 15:04") } diff --git a/internal/storage/processingstatus/ProcessingStatus_test.go b/internal/storage/processingstatus/ProcessingStatus_test.go new file mode 100644 index 00000000..fa41ef7e --- /dev/null +++ b/internal/storage/processingstatus/ProcessingStatus_test.go @@ -0,0 +1,66 @@ +package processingstatus + +import ( + "github.com/forceu/gokapi/internal/configuration" + "github.com/forceu/gokapi/internal/configuration/database" + "github.com/forceu/gokapi/internal/models" + "github.com/forceu/gokapi/internal/test" + "github.com/forceu/gokapi/internal/test/testconfiguration" + "github.com/r3labs/sse/v2" + "os" + "testing" + "time" +) + +func TestMain(m *testing.M) { + testconfiguration.Create(false) + configuration.Load() + exitVal := m.Run() + testconfiguration.Delete() + os.Exit(exitVal) +} + +func TestSetStatus(t *testing.T) { + + Init(sse.New()) + + chunkID := "testChunkID" + testCases := []struct { + name string + initialStatus int + newStatus int + }{ + {"SetNewStatus", -1, StatusHashingOrEncrypting}, + {"SetSameStatus", StatusUploading, StatusUploading}, + // Add more test cases as needed + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Set the initial status for the chunk ID + initialStatus := models.UploadStatus{ + ChunkId: chunkID, + CurrentStatus: tc.initialStatus, + LastUpdate: time.Now().Unix(), + } + database.SaveUploadStatus(initialStatus) + + // Set the new status + Set(chunkID, tc.newStatus) + + // Wait for SSE event to be published + time.Sleep(100 * time.Millisecond) + + // Retrieve the updated status from the database + updatedStatus, _ := database.GetUploadStatus(chunkID) + + // Check if the status was updated + test.IsEqualInt(t, tc.newStatus, updatedStatus.CurrentStatus) + }) + } + + sseServer = nil + defer test.ExpectPanic(t) + passNewStatus(models.UploadStatus{}) + +}