From 5946ca77761da59a47b81427cf20ad6c8ba97965 Mon Sep 17 00:00:00 2001 From: ffforest Date: Fri, 16 Aug 2024 14:08:51 +0800 Subject: [PATCH] fix: unit test errors --- pkg/domain/request/util.go | 4 +- .../terraform/tfops/test_data/plan.out.json | 86 +++++++++++++++ pkg/infra/persistence/backend_test.go | 5 +- pkg/infra/persistence/organization_test.go | 5 +- pkg/infra/persistence/project_test.go | 9 +- pkg/infra/persistence/source.go | 1 - pkg/infra/persistence/source_test.go | 5 +- pkg/infra/persistence/stack_test.go | 9 +- pkg/infra/persistence/workspace_test.go | 5 +- pkg/server/handler/backend/handler_test.go | 16 ++- .../handler/organization/handler_test.go | 16 ++- pkg/server/handler/project/handler_test.go | 40 +++---- pkg/server/handler/resource/handler_test.go | 101 ++++++++++++++++++ pkg/server/handler/source/handler_test.go | 15 ++- pkg/server/handler/stack/handler_test.go | 18 ++-- pkg/server/handler/workspace/handler_test.go | 15 ++- pkg/server/manager/stack/util.go | 2 +- 17 files changed, 260 insertions(+), 92 deletions(-) create mode 100644 pkg/engine/runtime/terraform/tfops/test_data/plan.out.json create mode 100644 pkg/server/handler/resource/handler_test.go diff --git a/pkg/domain/request/util.go b/pkg/domain/request/util.go index d3868c7c..d08bfb53 100644 --- a/pkg/domain/request/util.go +++ b/pkg/domain/request/util.go @@ -29,11 +29,11 @@ func decode(r *http.Request, payload interface{}) error { func validPath(path string) bool { // Validate project and stack path contains one or more capturing group // that contains a backslash with alphanumeric and underscore characters - return !regexp.MustCompile(`^([\/a-zA-Z0-9_])+$`).MatchString(path) + return !regexp.MustCompile(`^([\/a-zA-Z0-9_-])+$`).MatchString(path) } func validName(name string) bool { // Validate project, stack and appconfig name contains only alphanumeric // and underscore characters - return !regexp.MustCompile(`^[a-zA-Z0-9_]+$`).MatchString(name) + return !regexp.MustCompile(`^[a-zA-Z0-9_-]+$`).MatchString(name) } diff --git a/pkg/engine/runtime/terraform/tfops/test_data/plan.out.json b/pkg/engine/runtime/terraform/tfops/test_data/plan.out.json new file mode 100644 index 00000000..1534e258 --- /dev/null +++ b/pkg/engine/runtime/terraform/tfops/test_data/plan.out.json @@ -0,0 +1,86 @@ +{ + "format_version": "1.0", + "terraform_version": "1.1.0", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "local_file.kusion_example", + "mode": "managed", + "type": "local_file", + "name": "kusion_example", + "provider_name": "registry.terraform.io/hashicorp/local", + "schema_version": 0, + "values": { + "content": "kusion", + "content_base64": null, + "directory_permission": "0777", + "file_permission": "0777", + "filename": "test.txt", + "sensitive_content": null, + "source": null + } + } + ] + } + }, + "resource_changes": [ + { + "address": "local_file.kusion_example", + "mode": "managed", + "type": "local_file", + "name": "kusion_example", + "provider_name": "registry.terraform.io/hashicorp/local", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "content": "kusion", + "content_base64": null, + "directory_permission": "0777", + "file_permission": "0777", + "filename": "test.txt", + "sensitive_content": null, + "source": null + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": { + "sensitive_content": true + } + } + } + ], + "configuration": { + "provider_config": { + "local": { + "name": "local", + "version_constraint": "2.2.3" + } + }, + "root_module": { + "resources": [ + { + "address": "local_file.kusion_example", + "mode": "managed", + "type": "local_file", + "name": "kusion_example", + "provider_config_key": "local", + "expressions": { + "content": { + "constant_value": "kusion" + }, + "filename": { + "constant_value": "test.txt" + } + }, + "schema_version": 0 + } + ] + } + } +} \ No newline at end of file diff --git a/pkg/infra/persistence/backend_test.go b/pkg/infra/persistence/backend_test.go index 59d916d5..80361452 100644 --- a/pkg/infra/persistence/backend_test.go +++ b/pkg/infra/persistence/backend_test.go @@ -49,13 +49,12 @@ func TestBackendRepository(t *testing.T) { defer CloseDB(t, fakeGDB) defer sqlMock.ExpectClose() - var expectedID, expectedRows uint = 1, 1 + var expectedID uint = 1 sqlMock.ExpectBegin() sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(expectedRows))) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(0))) sqlMock.ExpectCommit() err = repo.Delete(context.Background(), expectedID) require.NoError(t, err) diff --git a/pkg/infra/persistence/organization_test.go b/pkg/infra/persistence/organization_test.go index 06c8b0e5..be801dc0 100644 --- a/pkg/infra/persistence/organization_test.go +++ b/pkg/infra/persistence/organization_test.go @@ -42,13 +42,12 @@ func TestOrganizationRepository(t *testing.T) { defer CloseDB(t, fakeGDB) defer sqlMock.ExpectClose() - var expectedID, expectedRows uint = 1, 1 + var expectedID uint = 1 sqlMock.ExpectBegin() sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(expectedRows))) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(0))) sqlMock.ExpectCommit() err = repo.Delete(context.Background(), expectedID) require.NoError(t, err) diff --git a/pkg/infra/persistence/project_test.go b/pkg/infra/persistence/project_test.go index 7480d173..a79d8f71 100644 --- a/pkg/infra/persistence/project_test.go +++ b/pkg/infra/persistence/project_test.go @@ -34,7 +34,9 @@ func TestProjectRepository(t *testing.T) { Remote: mockRemoteURL, }, Organization: &entity.Organization{ - ID: 1, + Name: "mockedOrg", + ID: 1, + Owners: []string{"hua.li", "xiaoming.li"}, }, Path: "/path/to/project", Labels: []string{"testLabel"}, @@ -57,13 +59,12 @@ func TestProjectRepository(t *testing.T) { defer CloseDB(t, fakeGDB) defer sqlMock.ExpectClose() - var expectedID, expectedRows uint = 1, 1 + var expectedID uint = 1 sqlMock.ExpectBegin() sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(expectedRows))) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(0))) sqlMock.ExpectCommit() err = repo.Delete(context.Background(), expectedID) require.NoError(t, err) diff --git a/pkg/infra/persistence/source.go b/pkg/infra/persistence/source.go index 207f9583..d93da71e 100644 --- a/pkg/infra/persistence/source.go +++ b/pkg/infra/persistence/source.go @@ -116,7 +116,6 @@ func (r *sourceRepository) Get(ctx context.Context, id uint) (*entity.Source, er if err != nil { return nil, err } - return dataModel.ToEntity() } diff --git a/pkg/infra/persistence/source_test.go b/pkg/infra/persistence/source_test.go index 5a81d154..99a5f1d4 100644 --- a/pkg/infra/persistence/source_test.go +++ b/pkg/infra/persistence/source_test.go @@ -50,13 +50,12 @@ func TestSourceRepository(t *testing.T) { defer CloseDB(t, fakeGDB) defer sqlMock.ExpectClose() - var expectedID, expectedRows uint = 1, 1 + var expectedID uint = 1 sqlMock.ExpectBegin() sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(expectedRows))) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(0))) sqlMock.ExpectCommit() err = repo.Delete(context.Background(), expectedID) require.NoError(t, err) diff --git a/pkg/infra/persistence/stack_test.go b/pkg/infra/persistence/stack_test.go index b9c17f11..63b3bce2 100644 --- a/pkg/infra/persistence/stack_test.go +++ b/pkg/infra/persistence/stack_test.go @@ -39,7 +39,9 @@ func TestStackRepository(t *testing.T) { Remote: mockRemoteURL, }, Organization: &entity.Organization{ - ID: 1, + Name: "mockedOrg", + ID: 1, + Owners: []string{"hua.li", "xiaoming.li"}, }, }, Path: "/path/to/stack", @@ -66,13 +68,12 @@ func TestStackRepository(t *testing.T) { defer CloseDB(t, fakeGDB) defer sqlMock.ExpectClose() - var expectedID, expectedRows uint = 1, 1 + var expectedID uint = 1 sqlMock.ExpectBegin() sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(expectedRows))) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(0))) sqlMock.ExpectCommit() err = repo.Delete(context.Background(), expectedID) require.NoError(t, err) diff --git a/pkg/infra/persistence/workspace_test.go b/pkg/infra/persistence/workspace_test.go index bf477c8f..dfdb9515 100644 --- a/pkg/infra/persistence/workspace_test.go +++ b/pkg/infra/persistence/workspace_test.go @@ -43,13 +43,12 @@ func TestWorkspaceRepository(t *testing.T) { defer CloseDB(t, fakeGDB) defer sqlMock.ExpectClose() - var expectedID, expectedRows uint = 1, 1 + var expectedID uint = 1 sqlMock.ExpectBegin() sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(expectedRows))) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(int64(expectedID), int64(0))) sqlMock.ExpectCommit() err = repo.Delete(context.Background(), expectedID) require.NoError(t, err) diff --git a/pkg/server/handler/backend/handler_test.go b/pkg/server/handler/backend/handler_test.go index d01b76ee..a8d1e800 100644 --- a/pkg/server/handler/backend/handler_test.go +++ b/pkg/server/handler/backend/handler_test.go @@ -63,7 +63,7 @@ func TestBackendHandler(t *testing.T) { AddRow(1, backendName)) // Create a new HTTP request - req, err := http.NewRequest("GET", "/backend/{backendID}", nil) + req, err := http.NewRequest("GET", "/backends/{backendID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -92,11 +92,10 @@ func TestBackendHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("POST", "/backend/{backendID}", nil) + req, err := http.NewRequest("POST", "/backends", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() - rctx.URLParams.Add("backendID", "1") req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) // Set request body @@ -135,7 +134,7 @@ func TestBackendHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/backend/{backendID}", nil) + req, err := http.NewRequest("POST", "/backends/{backendID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -183,7 +182,7 @@ func TestBackendHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/backend/{backendID}", nil) + req, err := http.NewRequest("DELETE", "/backends/{backendID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -195,8 +194,7 @@ func TestBackendHandler(t *testing.T) { sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(1, 1)) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(1, 0)) sqlMock.ExpectCommit() // Call the DeleteBackend handler function @@ -219,7 +217,7 @@ func TestBackendHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/backend/{backendID}", nil) + req, err := http.NewRequest("DELETE", "/backends/{backendID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -250,7 +248,7 @@ func TestBackendHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/backend/{backendID}", nil) + req, err := http.NewRequest("POST", "/backends/{backendID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() diff --git a/pkg/server/handler/organization/handler_test.go b/pkg/server/handler/organization/handler_test.go index f478879f..e6de8a44 100644 --- a/pkg/server/handler/organization/handler_test.go +++ b/pkg/server/handler/organization/handler_test.go @@ -65,7 +65,7 @@ func TestOrganizationHandler(t *testing.T) { AddRow(1, orgName)) // Create a new HTTP request - req, err := http.NewRequest("GET", "/organization/{organizationID}", nil) + req, err := http.NewRequest("GET", "/organizations/{organizationID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -94,11 +94,10 @@ func TestOrganizationHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("POST", "/organization/{organizationID}", nil) + req, err := http.NewRequest("POST", "/organizations", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() - rctx.URLParams.Add("organizationID", "1") req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) // Set request body @@ -138,7 +137,7 @@ func TestOrganizationHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/organization/{organizationID}", nil) + req, err := http.NewRequest("POST", "/organizations/{organizationID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -186,7 +185,7 @@ func TestOrganizationHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/organization/{organizationID}", nil) + req, err := http.NewRequest("DELETE", "/organizations/{organizationID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -198,8 +197,7 @@ func TestOrganizationHandler(t *testing.T) { sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(1, 1)) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(1, 0)) sqlMock.ExpectCommit() // Call the DeleteOrganization handler function @@ -222,7 +220,7 @@ func TestOrganizationHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/organization/{organizationID}", nil) + req, err := http.NewRequest("DELETE", "/organizations/{organizationID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -253,7 +251,7 @@ func TestOrganizationHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/organization/{organizationID}", nil) + req, err := http.NewRequest("POST", "/organizations/{organizationID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() diff --git a/pkg/server/handler/project/handler_test.go b/pkg/server/handler/project/handler_test.go index 6da20536..273d89fb 100644 --- a/pkg/server/handler/project/handler_test.go +++ b/pkg/server/handler/project/handler_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" "net/http" "net/http/httptest" @@ -28,7 +29,7 @@ func TestProjectHandler(t *testing.T) { projectNameSecond = "test-project-2" projectPath = "/path/to/project" projectNameUpdated = "test-project-updated" - projectPathUpdated = "/path/to/project/updated" + projectPathUpdated = "/path/to/projects/updated" owners = persistence.MultiString{"hua.li", "xiaoming.li"} ) t.Run("ListProjects", func(t *testing.T) { @@ -70,7 +71,7 @@ func TestProjectHandler(t *testing.T) { AddRow(1, projectName, projectPath, 1, "test-org", owners, 1, "https://github.com/test/repo", constant.SourceProviderTypeGithub)) // Create a new HTTP request - req, err := http.NewRequest("GET", "/project/{projectID}", nil) + req, err := http.NewRequest("GET", "/projects/{projectID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -99,11 +100,10 @@ func TestProjectHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("POST", "/project/{projectID}", nil) + req, err := http.NewRequest("POST", "/projects", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() - rctx.URLParams.Add("projectID", "1") req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) // Set request body @@ -151,7 +151,7 @@ func TestProjectHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("PUT", "/project/{projectID}", nil) + req, err := http.NewRequest("PUT", "/projects/{projectID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -166,7 +166,6 @@ func TestProjectHandler(t *testing.T) { Name: projectNameUpdated, Path: projectPathUpdated, OrganizationID: 1, - SourceID: 1, }, } reqBody, err := json.Marshal(requestPayload) @@ -174,9 +173,6 @@ func TestProjectHandler(t *testing.T) { req.Body = io.NopCloser(bytes.NewReader(reqBody)) req.Header.Add("Content-Type", "application/json") - sqlMock.ExpectQuery("SELECT"). - WillReturnRows(sqlmock.NewRows([]string{"id", "remote", "source_provider"}). - AddRow(1, "https://github.com/test/repo", constant.SourceProviderTypeGithub)) sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id", "name", "owners"}). AddRow(1, "test-org", owners)) @@ -190,6 +186,8 @@ func TestProjectHandler(t *testing.T) { projectHandler.UpdateProject()(recorder, req) assert.Equal(t, http.StatusOK, recorder.Code) + fmt.Println(recorder.Body.String()) + // Unmarshall the response body var resp handler.Response err = json.Unmarshal(recorder.Body.Bytes(), &resp) @@ -209,7 +207,7 @@ func TestProjectHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/project/{projectID}", nil) + req, err := http.NewRequest("DELETE", "/projects/{projectID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -221,8 +219,7 @@ func TestProjectHandler(t *testing.T) { sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(1, 1)) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(1, 0)) sqlMock.ExpectCommit() // Call the DeleteProject handler function @@ -245,7 +242,7 @@ func TestProjectHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/project/{projectID}", nil) + req, err := http.NewRequest("DELETE", "/projects/{projectID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -276,20 +273,21 @@ func TestProjectHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/project/{projectID}", nil) + req, err := http.NewRequest("POST", "/projects/{projectID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() - rctx.URLParams.Add("projectID", "1") + rctx.URLParams.Add("projectID", "2") req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) // Set request body requestPayload := request.UpdateProjectRequest{ // Set your request payload fields here - ID: 1, + ID: 2, CreateProjectRequest: request.CreateProjectRequest{ - Name: "test-project-updated", - Path: projectPathUpdated, + Name: "test-project-updated", + Path: projectPathUpdated, + OrganizationID: 1, }, } reqBody, err := json.Marshal(requestPayload) @@ -297,12 +295,6 @@ func TestProjectHandler(t *testing.T) { req.Body = io.NopCloser(bytes.NewReader(reqBody)) req.Header.Add("Content-Type", "application/json") - sqlMock.ExpectQuery("SELECT"). - WillReturnRows(sqlmock.NewRows([]string{"id", "remote", "source_provider"}). - AddRow(1, "https://github.com/test/repo", constant.SourceProviderTypeGithub)) - sqlMock.ExpectQuery("SELECT"). - WillReturnRows(sqlmock.NewRows([]string{"id", "name", "owners"}). - AddRow(1, "test-org", owners)) sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"})) diff --git a/pkg/server/handler/resource/handler_test.go b/pkg/server/handler/resource/handler_test.go new file mode 100644 index 00000000..86670c75 --- /dev/null +++ b/pkg/server/handler/resource/handler_test.go @@ -0,0 +1,101 @@ +package resource + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-chi/chi/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gorm.io/gorm" + "kusionstack.io/kusion/pkg/infra/persistence" + "kusionstack.io/kusion/pkg/server/handler" + resourcemanager "kusionstack.io/kusion/pkg/server/manager/resource" +) + +func TestResourceHandler(t *testing.T) { + var ( + resourceName = "test-resource" + resourceNameSecond = "test-resource-2" + ) + t.Run("ListResources", func(t *testing.T) { + sqlMock, fakeGDB, recorder, stackHandler := setupTest(t) + defer persistence.CloseDB(t, fakeGDB) + defer sqlMock.ExpectClose() + + sqlMock.ExpectQuery("SELECT"). + WillReturnRows(sqlmock.NewRows([]string{"id", "resource_type", "resource_plane", "resource_name", "kusion_resource_id"}). + AddRow(1, "Kubernetes", "Kubernetes", resourceName, "a:b:c:d"). + AddRow(2, "Terraform", "AWS", resourceNameSecond, "e:f:g:h")) + + // Create a new HTTP request + req, err := http.NewRequest("GET", "/resources", nil) + assert.NoError(t, err) + + // Call the ListResources handler function + stackHandler.ListResources()(recorder, req) + assert.Equal(t, http.StatusOK, recorder.Code) + + // Unmarshall the response body + var resp handler.Response + err = json.Unmarshal(recorder.Body.Bytes(), &resp) + if err != nil { + t.Fatalf("Failed to unmarshal response: %v", err) + } + + // Assertion + assert.Equal(t, 2, len(resp.Data.([]any))) + }) + + t.Run("GetResource", func(t *testing.T) { + sqlMock, fakeGDB, recorder, resourceHandler := setupTest(t) + defer persistence.CloseDB(t, fakeGDB) + defer sqlMock.ExpectClose() + + sqlMock.ExpectQuery("SELECT"). + WillReturnRows(sqlmock.NewRows([]string{"id", "resource_type", "resource_plane", "resource_name", "kusion_resource_id"}). + AddRow(1, "Kubernetes", "Kubernetes", resourceName, "a:b:c:d")) + + // Create a new HTTP request + req, err := http.NewRequest("GET", "/resources/{resourceID}", nil) + assert.NoError(t, err) + + rctx := chi.NewRouteContext() + rctx.URLParams.Add("resourceID", "1") + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + // Call the ListResources handler function + resourceHandler.GetResource()(recorder, req) + fmt.Println(recorder.Body.String()) + assert.Equal(t, http.StatusOK, recorder.Code) + + // Unmarshal the response body + var resp handler.Response + err = json.Unmarshal(recorder.Body.Bytes(), &resp) + if err != nil { + t.Fatalf("Failed to unmarshal response: %v", err) + } + + // Assertion + assert.Equal(t, float64(1), resp.Data.(map[string]any)["id"]) + assert.Equal(t, resourceName, resp.Data.(map[string]any)["resourceName"]) + assert.Equal(t, "Kubernetes", resp.Data.(map[string]any)["resourceType"]) + assert.Equal(t, "Kubernetes", resp.Data.(map[string]any)["resourcePlane"]) + }) +} + +func setupTest(t *testing.T) (sqlmock.Sqlmock, *gorm.DB, *httptest.ResponseRecorder, *Handler) { + fakeGDB, sqlMock, err := persistence.GetMockDB() + require.NoError(t, err) + resourceRepo := persistence.NewResourceRepository(fakeGDB) + resourceHandler := &Handler{ + resourceManager: resourcemanager.NewResourceManager(resourceRepo), + } + recorder := httptest.NewRecorder() + return sqlMock, fakeGDB, recorder, resourceHandler +} diff --git a/pkg/server/handler/source/handler_test.go b/pkg/server/handler/source/handler_test.go index 23376a60..486dc506 100644 --- a/pkg/server/handler/source/handler_test.go +++ b/pkg/server/handler/source/handler_test.go @@ -63,7 +63,7 @@ func TestSourceHandler(t *testing.T) { AddRow(1, string(constant.SourceProviderTypeGithub))) // Create a new HTTP request - req, err := http.NewRequest("GET", "/source/{sourceID}", nil) + req, err := http.NewRequest("GET", "/sources/{sourceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -92,7 +92,7 @@ func TestSourceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("POST", "/source/{sourceID}", nil) + req, err := http.NewRequest("POST", "/sources", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -137,7 +137,7 @@ func TestSourceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/source/{sourceID}", nil) + req, err := http.NewRequest("POST", "/sources/{sourceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -185,7 +185,7 @@ func TestSourceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/source/{sourceID}", nil) + req, err := http.NewRequest("DELETE", "/sources/{sourceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -197,8 +197,7 @@ func TestSourceHandler(t *testing.T) { sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(1, 1)) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(1, 0)) sqlMock.ExpectCommit() // Call the DeleteSource handler function @@ -221,7 +220,7 @@ func TestSourceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/source/{sourceID}", nil) + req, err := http.NewRequest("DELETE", "/sources/{sourceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -252,7 +251,7 @@ func TestSourceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/source/{sourceID}", nil) + req, err := http.NewRequest("POST", "/sources/{sourceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() diff --git a/pkg/server/handler/stack/handler_test.go b/pkg/server/handler/stack/handler_test.go index cdfb6c3f..b7220b25 100644 --- a/pkg/server/handler/stack/handler_test.go +++ b/pkg/server/handler/stack/handler_test.go @@ -30,7 +30,7 @@ func TestStackHandler(t *testing.T) { projectPath = "/path/to/project" stackPath = "/path/to/stack" stackNameUpdated = "test-stack-updated" - stackPathUpdated = "/path/to/stack/updated" + stackPathUpdated = "/path/to/stacks/updated" owners = persistence.MultiString{"hua.li", "xiaoming.li"} ) t.Run("ListStacks", func(t *testing.T) { @@ -72,7 +72,7 @@ func TestStackHandler(t *testing.T) { AddRow(1, stackName, stackPath, constant.StackStateUnSynced, 1, projectName, projectPath)) // Create a new HTTP request - req, err := http.NewRequest("GET", "/stack/{stackID}", nil) + req, err := http.NewRequest("GET", "/stacks/{stackID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -103,11 +103,10 @@ func TestStackHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("POST", "/stack/{stackID}", nil) + req, err := http.NewRequest("POST", "/stacks", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() - rctx.URLParams.Add("stackID", "1") req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) // Set request body @@ -155,7 +154,7 @@ func TestStackHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("PUT", "/stack/{stackID}", nil) + req, err := http.NewRequest("PUT", "/stacks/{stackID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -209,7 +208,7 @@ func TestStackHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/stack/{stackID}", nil) + req, err := http.NewRequest("DELETE", "/stacks/{stackID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -221,8 +220,7 @@ func TestStackHandler(t *testing.T) { sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(1, 1)) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(1, 0)) sqlMock.ExpectCommit() // Call the DeleteStack handler function @@ -245,7 +243,7 @@ func TestStackHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/stack/{stackID}", nil) + req, err := http.NewRequest("DELETE", "/stacks/{stackID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -276,7 +274,7 @@ func TestStackHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/stack/{stackID}", nil) + req, err := http.NewRequest("POST", "/stacks/{stackID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() diff --git a/pkg/server/handler/workspace/handler_test.go b/pkg/server/handler/workspace/handler_test.go index e7b46689..34480b69 100644 --- a/pkg/server/handler/workspace/handler_test.go +++ b/pkg/server/handler/workspace/handler_test.go @@ -65,7 +65,7 @@ func TestWorkspaceHandler(t *testing.T) { AddRow(1, wsName, 1)) // Create a new HTTP request - req, err := http.NewRequest("GET", "/workspace/{workspaceID}", nil) + req, err := http.NewRequest("GET", "/workspaces/{workspaceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -94,7 +94,7 @@ func TestWorkspaceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("POST", "/workspace/{workspaceID}", nil) + req, err := http.NewRequest("POST", "/workspaces", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -142,7 +142,7 @@ func TestWorkspaceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/workspace/{workspaceID}", nil) + req, err := http.NewRequest("POST", "/workspaces/{workspaceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -188,7 +188,7 @@ func TestWorkspaceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/workspace/{workspaceID}", nil) + req, err := http.NewRequest("DELETE", "/workspaces/{workspaceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -200,8 +200,7 @@ func TestWorkspaceHandler(t *testing.T) { sqlMock.ExpectQuery("SELECT"). WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow(1)) - sqlMock.ExpectExec("UPDATE"). - WillReturnResult(sqlmock.NewResult(1, 1)) + sqlMock.ExpectExec("DELETE").WillReturnResult(sqlmock.NewResult(1, 0)) sqlMock.ExpectCommit() // Call the DeleteWorkspace handler function @@ -224,7 +223,7 @@ func TestWorkspaceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Create a new HTTP request - req, err := http.NewRequest("DELETE", "/workspace/{workspaceID}", nil) + req, err := http.NewRequest("DELETE", "/workspaces/{workspaceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() @@ -255,7 +254,7 @@ func TestWorkspaceHandler(t *testing.T) { defer sqlMock.ExpectClose() // Update a new HTTP request - req, err := http.NewRequest("POST", "/workspace/{workspaceID}", nil) + req, err := http.NewRequest("POST", "/workspaces/{workspaceID}", nil) assert.NoError(t, err) rctx := chi.NewRouteContext() diff --git a/pkg/server/manager/stack/util.go b/pkg/server/manager/stack/util.go index 6a00b13f..451240c8 100644 --- a/pkg/server/manager/stack/util.go +++ b/pkg/server/manager/stack/util.go @@ -192,7 +192,7 @@ func buildValidStackPath(requestPayload request.CreateStackRequest, projectEntit func validStackPath(path string) bool { // Validate stack path contains one or more capturing group // that contains a backslash with alphanumeric and underscore characters - return regexp.MustCompile(`^([\/a-zA-Z0-9_])+$`).MatchString(path) + return regexp.MustCompile(`^([\/a-zA-Z0-9_-])+$`).MatchString(path) } func tempPath(path string) string {