diff --git a/src/cli-client/internals/cli/validator_test.go b/src/cli-client/internals/cli/validator_test.go new file mode 100644 index 000000000..27577fc3c --- /dev/null +++ b/src/cli-client/internals/cli/validator_test.go @@ -0,0 +1,29 @@ +package cli_test + +import ( + "testing" + + "github.com/canonical/oci-factory/cli-client/internals/cli" +) + +func TestValidateAndFormatDateLegalInput(t *testing.T) { + inputs := []string{"2006-07-08", "2008-09-10", "2024-05-01"} + + for _, datetime := range inputs { + _, err := cli.ValidateAndFormatDate(datetime) + if err != nil { + t.Fatalf("Failed parsing legal time format yyyy-mm-dd, %v", err) + } + } +} + +func TestValidateAndFormatDateBadInput(t *testing.T) { + inputs := []string{"2001-02-29", "2024-05-32", "01-01-2023"} + + for _, datetime := range inputs { + _, err := cli.ValidateAndFormatDate(datetime) + if err == nil { + t.Fatalf("Parsing illegal date input [%s] didn't raise error", datetime) + } + } +} diff --git a/src/cli-client/internals/client/client_test.go b/src/cli-client/internals/client/client_test.go new file mode 100644 index 000000000..7a30300ea --- /dev/null +++ b/src/cli-client/internals/client/client_test.go @@ -0,0 +1,46 @@ +package client_test + +import ( + "bytes" + "io" + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/canonical/oci-factory/cli-client/internals/client" + "github.com/canonical/oci-factory/cli-client/internals/token" +) + +func TestSendRequest(t *testing.T) { + mockPayload := []byte(`{"mock":"payload"}`) + expectedStatusCode := http.StatusOK + + // Create a mock server + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Verify the request method, URL, and payload + if r.Method != http.MethodPost { + t.Errorf("unexpected request method, want POST, got %s", r.Method) + } + body, _ := io.ReadAll(r.Body) + if !bytes.Equal(body, mockPayload) { + t.Errorf("unexpected request payload, want %s, got %s", string(mockPayload), string(body)) + } + // Set the response status code and body + w.WriteHeader(expectedStatusCode) + w.Write([]byte(`{"mock":"response"}`)) + })) + defer mockServer.Close() + + saveToken := os.Getenv(token.TokenVarName) + os.Setenv(token.TokenVarName, "ghp_AAAAAAAA") + // Call the SendRequest function + response := client.SendRequest(http.MethodPost, mockServer.URL, mockPayload, expectedStatusCode) + token.RestoreTokenEnv(saveToken) + + // Verify the response + expectedResponse := []byte(`{"mock":"response"}`) + if !bytes.Equal(response, expectedResponse) { + t.Errorf("unexpected response, want %s, got %s", string(expectedResponse), string(response)) + } +} diff --git a/src/cli-client/internals/client/wf_dispatcher_test.go b/src/cli-client/internals/client/wf_dispatcher_test.go index fb28aa71e..5e58f944e 100644 --- a/src/cli-client/internals/client/wf_dispatcher_test.go +++ b/src/cli-client/internals/client/wf_dispatcher_test.go @@ -2,8 +2,11 @@ package client_test import ( "bytes" + "encoding/json" "fmt" + "io" "net/http" + "net/http/httptest" "os" "testing" @@ -11,6 +14,18 @@ import ( "github.com/canonical/oci-factory/cli-client/internals/token" ) +func testHeaderEntriesEqual(header1 map[string][]string, header2 map[string]string) bool { + for key, value := range header2 { + fmt.Println(key, header1[key]) + fmt.Println(key, header2[key]) + fmt.Println(key, header1[key][0]) + if header1[key][0] != value { + return false + } + } + return true +} + func TestSetHeaderWithMap(t *testing.T) { mockUrl := "https://mock.url" mockJson := []byte(`{"mock":"json"}`) @@ -27,3 +42,41 @@ func TestSetHeaderWithMap(t *testing.T) { t.Fatalf("request 1 not equals to request 2\nrequest1: %+v\nrequest2: %+v", request1, request2) } } + +func TestDispatchWorkflow(t *testing.T) { + mockJson := []byte(`{"mock":"json"}`) + saveToken := token.UpdateEnvToken("ghp_AAAAAAAA") + header := client.NewGithubAuthHeaderMap() + + expectedPayload := client.NewPayload("image-name", "image-trigger") + expectedPayloadJSON, _ := json.Marshal(expectedPayload) + + // Create a mock server + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Verify the request method, URL, and payload + if r.Method != http.MethodPost { + t.Fatalf("unexpected request method, want POST, got %s", r.Method) + } + // Verify the request header + // TODO received header is missing X-GitHub-Api-Version + if !testHeaderEntriesEqual(r.Header, header) { + t.Fatalf("unexpected request header, want %v, got %v", header, r.Header) + } + // header setting is tested above and transferring is tested in the http library + body, _ := io.ReadAll(r.Body) + if !bytes.Equal(body, expectedPayloadJSON) { + t.Fatalf("unexpected request payload, want %s, got %s", string(expectedPayloadJSON), string(body)) + } + // Set the no content response status code and body + w.WriteHeader(http.StatusNoContent) + w.Write([]byte(``)) + })) + defer mockServer.Close() + + request, _ := http.NewRequest(http.MethodPost, mockServer.URL, bytes.NewBuffer(mockJson)) + client.SetHeaderWithMap(request, header) + + // Call the DispatchWorkflow function + client.DispatchWorkflowImpl_(expectedPayload, mockServer.URL) + token.RestoreTokenEnv(saveToken) +} diff --git a/src/cli-client/internals/client/wf_poller_test.go b/src/cli-client/internals/client/wf_poller_test.go new file mode 100644 index 000000000..94780d505 --- /dev/null +++ b/src/cli-client/internals/client/wf_poller_test.go @@ -0,0 +1,43 @@ +package client_test + +import ( + "testing" + + "github.com/canonical/oci-factory/cli-client/internals/client" +) + +func TestGetWorkflowRunStatusFromResp(t *testing.T) { + mockResponseBody := []byte(`{"status":"completed","conclusion":"success"}`) + expectedStatus := "completed" + expectedConclusion := "success" + + status, conclusion := client.GetWorkflowRunStatusFromResp(mockResponseBody) + + // Verify the response + if status != expectedStatus { + t.Errorf("unexpected status, want %s, got %s", expectedStatus, status) + } + if conclusion != expectedConclusion { + t.Errorf("unexpected conclusion, want %s, got %s", expectedConclusion, conclusion) + } +} + +func TestGetWorkflowJobsProgressFromResp(t *testing.T) { + mockResponseBody := []byte(`{"jobs":[{"name":"Job 1","status":"completed"},{"name":"Job 2","status":"in_progress"},{"name":"Job 3","status":"queued"}]}`) + expectedCurrJob := 2 + expectedTotalJobs := 3 + expectedJobName := "Job 2" + + currJob, totalJobs, jobName := client.GetWorkflowJobsProgressFromResp(mockResponseBody) + + // Verify the response + if currJob != expectedCurrJob { + t.Errorf("unexpected current job, want %d, got %d", expectedCurrJob, currJob) + } + if totalJobs != expectedTotalJobs { + t.Errorf("unexpected total jobs, want %d, got %d", expectedTotalJobs, totalJobs) + } + if jobName != expectedJobName { + t.Errorf("unexpected job name, want %s, got %s", expectedJobName, jobName) + } +} diff --git a/src/cli-client/internals/token/token.go b/src/cli-client/internals/token/token.go index c34b3bbb4..c0ad8d041 100644 --- a/src/cli-client/internals/token/token.go +++ b/src/cli-client/internals/token/token.go @@ -8,6 +8,8 @@ import ( "golang.org/x/term" ) +const TokenVarName = "GITHUB_TOKEN" + var _accessToken = "" func readAccessToken() string { @@ -33,3 +35,17 @@ func GetAccessToken() string { } return _accessToken } + +func RestoreTokenEnv(saveToken string) { + if len(saveToken) == 0 { + os.Unsetenv(TokenVarName) + } else { + os.Setenv(TokenVarName, saveToken) + } +} + +func UpdateEnvToken(token string) string { + saveToken := os.Getenv(TokenVarName) + os.Setenv(TokenVarName, token) + return saveToken +} diff --git a/src/cli-client/internals/token/token_test.go b/src/cli-client/internals/token/token_test.go new file mode 100644 index 000000000..ce5e5eebb --- /dev/null +++ b/src/cli-client/internals/token/token_test.go @@ -0,0 +1,25 @@ +package token_test + +import ( + "os" + "testing" + + "github.com/canonical/oci-factory/cli-client/internals/token" +) + +func TestReadAccessTokenEnv(t *testing.T) { + expectedToken := "ghp_test123ToKeN" + saveToken := token.UpdateEnvToken(expectedToken) + err := os.Setenv(token.TokenVarName, expectedToken) + if err != nil { + t.Fatalf("Unable to set env variable: %v", err) + } + resultToken := token.GetAccessToken() + if resultToken != expectedToken { + t.Fatalf("") + } + token.RestoreTokenEnv(saveToken) + if os.Getenv(token.TokenVarName) != saveToken { + t.Fatalf("Unable to restore saved env variable") + } +}