From 22d84a50051c1a6fc833e7b37b1c1044d721601b Mon Sep 17 00:00:00 2001 From: Dmitry Shurco Date: Tue, 8 Oct 2024 22:43:33 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AA=20test:=20tests=20for=20the=20REST?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/agent/agent_test.go | 124 + api/agent/routes_test.go | 25 + api/auth/auth_test.go | 524 ++-- api/auth/routes_test.go | 22 + api/event/event_test.go | 565 ++-- api/event/routes_test.go | 26 + api/key/key_test.go | 1498 ++++----- api/key/routes_test.go | 24 + api/license/license_test.go | 185 +- api/license/routes_test.go | 24 + api/member/project_test.go | 1648 +++++++++- api/member/routes_test.go | 27 + api/member/scheme_test.go | 1031 +++++++ api/ping/ping_test.go | 81 +- api/ping/routes_test.go | 15 + api/project/key_test.go | 646 ++++ api/project/project_test.go | 1219 +++++--- api/project/routes_test.go | 21 + api/scheme/routes_test.go | 50 + api/scheme/scheme_test.go | 3697 +++++++++++++++++++++++ api/scheme/user_test.go | 293 ++ api/system/info_test.go | 173 ++ api/system/routes_test.go | 28 + api/system/utility_test.go | 111 + api/user/routes_test.go | 21 + api/user/user_test.go | 904 ++++++ internal/grpc/account/account_test.go | 86 +- internal/grpc/event/event_test.go | 843 +++--- internal/grpc/firewall/firewall_test.go | 96 + internal/grpc/license/license_test.go | 44 +- internal/grpc/scheme/system_test.go | 299 ++ internal/grpc/scheme/user_test.go | 99 + 32 files changed, 11854 insertions(+), 2595 deletions(-) create mode 100644 api/agent/agent_test.go create mode 100644 api/agent/routes_test.go create mode 100644 api/auth/routes_test.go create mode 100644 api/event/routes_test.go create mode 100644 api/key/routes_test.go create mode 100644 api/license/routes_test.go create mode 100644 api/member/routes_test.go create mode 100644 api/member/scheme_test.go create mode 100644 api/ping/routes_test.go create mode 100644 api/project/key_test.go create mode 100644 api/project/routes_test.go create mode 100644 api/scheme/routes_test.go create mode 100644 api/scheme/scheme_test.go create mode 100644 api/scheme/user_test.go create mode 100644 api/system/info_test.go create mode 100644 api/system/routes_test.go create mode 100644 api/system/utility_test.go create mode 100644 api/user/routes_test.go create mode 100644 api/user/user_test.go create mode 100644 internal/grpc/firewall/firewall_test.go create mode 100644 internal/grpc/scheme/system_test.go create mode 100644 internal/grpc/scheme/user_test.go diff --git a/api/agent/agent_test.go b/api/agent/agent_test.go new file mode 100644 index 00000000..d3b405fa --- /dev/null +++ b/api/agent/agent_test.go @@ -0,0 +1,124 @@ +package agent + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/trace" + "github.com/werbot/werbot/internal/utils/test" +) + +func TestHandler_auth(t *testing.T) { + app, teardownTestCase, _, _ := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { + Name: "test0_01", + Method: http.MethodPost, + Path: test.PathGluing(pathAgent, "auth"), + StatusCode: 404, + Body: test.BodyNotFound, + }, + { + Name: "test0_02", + Method: http.MethodPost, + Path: test.PathGluing(pathAgent, "auth", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgTokenNotFound, + }, + }, + { + Name: "test0_03", + Method: http.MethodPost, + Path: test.PathGluing(pathAgent, "auth", "0a177fc3-ad38-40c6-b936-ded649ce5a57"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Auth data", + "result.api_key": "5tYJOkr3oLCOEvhw3nB83AmDzYM7yJsJ0Sonl", + "result.api_secret": "aDzYMy9g3mmsq3XazPLvvCbj4kJAsgatxBDVW", + "result.scheme_type": float64(103), + }, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addScheme(t *testing.T) { + app, teardownTestCase, adminHeader, _ := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { + Name: "test0_01", + Method: http.MethodPost, + Path: test.PathGluing(pathAgentScheme), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathAgentScheme), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathAgentScheme, test.ConstFakeID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.address": "value is required", + "result.port": "value is required", + "result.login": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathAgentScheme, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "address": "127.0.0.255", + "port": float64(2922), + "login": "ubuntu", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgTokenNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathAgentScheme, "0a177fc3-ad38-40c6-b936-ded649ce5a57"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "address": "127.0.0.255", + "port": float64(2922), + "login": "ubuntu", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme data", + "result.public_key": "*", + "result.scheme_id": "*", + }, + RequestHeaders: adminHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/agent/routes_test.go b/api/agent/routes_test.go new file mode 100644 index 00000000..fc6925f2 --- /dev/null +++ b/api/agent/routes_test.go @@ -0,0 +1,25 @@ +package agent + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathAgent = "/v1/agent" + pathAgentScheme = "/v1/agent/scheme" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader := map[string]string{"x-api-key": test.ConstAdminProject1ApiKey} + userHeader := map[string]string{"x-api-key": test.ConstUserProject1ApiKey} + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/auth/auth_test.go b/api/auth/auth_test.go index 911d9c8a..f759b31d 100644 --- a/api/auth/auth_test.go +++ b/api/auth/auth_test.go @@ -1,326 +1,282 @@ package auth -/* import ( "net/http" "testing" - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - accountpb "github.com/werbot/werbot/api/proto/account" - "github.com/werbot/werbot/api" - "github.com/werbot/werbot/internal" - "github.com/werbot/werbot/internal/tests" - "github.com/werbot/werbot/internal/web/jwt" -) - -var ( - testHandler *tests.TestHandler - adminInfo *tests.UserInfo - userInfo *tests.UserInfo + "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/crypto" + "github.com/werbot/werbot/pkg/utils/fsutil" ) -func init() { - testHandler = tests.InitTestServer("../../../.env") - New(&web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Cache: testHandler.Cache, - Auth: *testHandler.Auth, - }).Routes() - testHandler.FinishHandler() // init finale handler for apitest - - adminInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-admin@werbot.net", - Password: "test-admin@werbot.net", - }) - - userInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-user@werbot.net", - Password: "test-user@werbot.net", - }) -} - -func apiTest() *apitest.APITest { - return apitest.New(). - //Debug(). - HandlerFunc(testHandler.Handler) -} +func TestHandler_signin(t *testing.T) { + app, teardownTestCase := setupTest(t) + defer teardownTestCase(t) -func Test_signIn(t *testing.T) { - t.Parallel() - - testCases := map[string][]tests.TestCase{} - - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: map[string]string{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.email`, "email is a required field"). - Equal(`$.result.password`, "password is a required field"). - End(), - RespondStatus: http.StatusBadRequest, + testTable := []test.APITable{ + { // incorrect method + Name: "test0_01", + Method: http.MethodGet, + Path: pathAuthSignIn, + StatusCode: 404, + Body: test.BodyNotFound, }, - { - Name: "Error getting params", - RequestBody: []map[string]string{{"zz": "xx"}, {"xx": "zz"}}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - End(), - RespondStatus: http.StatusBadRequest, + { // clear request + Name: "test0_02", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + }, }, - { - Name: "Password is blank", - RequestBody: map[string]string{"email": "test-admin@werbot.net"}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.password`, "password is a required field"). - End(), - RespondStatus: http.StatusBadRequest, + { // clear body request + Name: "test0_03", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 400, + RequestBody: test.BodyTable{}, + Body: test.BodyTable{ + "code": float64(400), + "result.email": "value is required", + "result.password": "value is required", + }, }, - { - Name: "Email is blank", - RequestBody: map[string]string{"password": "test-admin@werbot.net"}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.email`, "email is a required field"). - End(), - RespondStatus: http.StatusBadRequest, + { // clear body request + Name: "test0_04", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": "email", + "password": "123", + }, + Body: test.BodyTable{ + "code": float64(400), + "result.email": "value must be a valid email address", + "result.password": "value length must be at least 8 characters", + }, }, - { - Name: "Invalid password", - RequestBody: map[string]string{"email": "test-admin@werbot.net", "password": "user@werbot.net"}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgPasswordIsNotValid). - End(), - RespondStatus: http.StatusBadRequest, + { // email requests only + Name: "test0_05", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": test.ConstAdminEmail, + }, + Body: test.BodyTable{ + "code": float64(400), + "result.password": "value is required", + }, }, - } - - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Valid admin login and password", - RequestBody: map[string]string{"email": "test-admin@werbot.net", "password": "test-admin@werbot.net"}, - RespondBody: jsonpath.Chain(). - Present(`access_token`). - Present(`refresh_token`). - End(), - RespondStatus: http.StatusOK, + { // password request only + Name: "test0_06", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 400, + RequestBody: test.BodyTable{ + "password": test.ConstAdminEmail, + }, + Body: test.BodyTable{ + "code": float64(400), + "result.email": "value is required", + }, }, - } - - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Valid user login and password", - RequestBody: map[string]string{"email": "test-user@werbot.net", "password": "test-user@werbot.net"}, - RespondBody: jsonpath.Chain(). - Present(`access_token`). - Present(`refresh_token`). - End(), - RespondStatus: http.StatusOK, + { // incorrect login + Name: "test0_07", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": test.ConstAdminEmail, + "password": crypto.NewPassword(1, false), + }, + Body: test.BodyTable{ + "code": float64(400), + "result.password": "value length must be at least 8 characters", + }, }, - } - - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Post("/auth/signin"). - JSON(tc.RequestBody). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } -} - -func Test_logout(t *testing.T) { - t.Parallel() - - testCases := []tests.TestCase{ - { - Name: "Authorized user logout", - RequestUser: adminInfo, - RespondStatus: http.StatusOK, + { // incorrect login or password + Name: "test0_08", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 404, + RequestBody: test.BodyTable{ + "email": test.ConstUnknownEmail, + "password": test.ConstUnknownPassword, + }, + Body: test.BodyNotFound, }, - { - Name: "No authorized user logout", - RequestUser: &tests.UserInfo{}, - RespondStatus: http.StatusUnauthorized, + { // ADMIN: authorization + Name: "test1_01", + Method: http.MethodPost, + Path: pathAuthSignIn, + StatusCode: 200, + RequestBody: test.BodyTable{ + "email": test.ConstAdminEmail, + "password": test.ConstAdminPassword, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Tokens", + "result.access_token": "*", + "result.refresh_token": "*", + }, }, } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Post("/auth/logout"). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Status(tc.RespondStatus). - End() - }) - } + test.RunCaseAPITests(t, app, testTable) } -func Test_refresh(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} +func TestHandler_logout(t *testing.T) { + app, teardownTestCase := setupTest(t) + defer teardownTestCase(t) - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: jwt.Tokens{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "token parsing error"). - End(), - RespondStatus: http.StatusBadRequest, - }, - } + adminAuth := app.GetUserAuth(test.ConstAdminEmail, test.ConstAdminPassword) + adminHeader := test.HeadersTable{"Authorization": "Bearer " + adminAuth.Tokens.Access} - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Authorized user refresh", - RequestUser: adminInfo, - RequestBody: jwt.Tokens{ - Refresh: adminInfo.Tokens.Refresh, - }, - RespondBody: jsonpath.Chain(). - Present(`access_token`). - Present(`refresh_token`). - End(), - RespondStatus: http.StatusOK, + userAuth := app.GetUserAuth(test.ConstUserEmail, test.ConstUserPassword) + userHeader := test.HeadersTable{"Authorization": "Bearer " + userAuth.Tokens.Access} + + testTable := []test.APITable{ + { // incorrect method + Name: "test0_01", + Method: http.MethodGet, + Path: pathAuthLogout, + StatusCode: 404, + Body: test.BodyNotFound, }, - { - Name: "Bad token error", - RequestUser: adminInfo, - RequestBody: jwt.Tokens{ - Refresh: adminInfo.Tokens.Refresh + "error", - }, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "token parsing error"). - End(), - RespondStatus: http.StatusBadRequest, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPost, + Path: pathAuthLogout, + StatusCode: 401, + Body: test.BodyUnauthorized, }, - } - - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Authorized user refresh", - RequestUser: userInfo, - RequestBody: jwt.Tokens{ - Refresh: userInfo.Tokens.Refresh, + { // ADMIN: authorized request + Name: "test1_01", + Method: http.MethodPost, + Path: pathAuthLogout, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Successful logout", }, - RespondBody: jsonpath.Chain(). - Present(`access_token`). - Present(`refresh_token`). - End(), - RespondStatus: http.StatusOK, + RequestHeaders: adminHeader, }, - { - Name: "Bad token error", - RequestUser: userInfo, - RequestBody: jwt.Tokens{ - Refresh: userInfo.Tokens.Refresh + "error", + { // USER: authorized request + Name: "test2_01", + Method: http.MethodPost, + Path: pathAuthLogout, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Successful logout", }, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "token parsing error"). - End(), - RespondStatus: http.StatusBadRequest, + RequestHeaders: userHeader, }, + // TODO add other test cases to logout } - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Post("/auth/refresh"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -func Test_getProfile(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} +func TestHandler_refresh(t *testing.T) { + app, teardownTestCase := setupTest(t) + defer teardownTestCase(t) - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - } + adminAuth := app.GetUserAuth(test.ConstAdminEmail, test.ConstAdminPassword) + adminHeader := test.HeadersTable{"Authorization": "Bearer " + adminAuth.Tokens.Access} - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Retrieval of user data", - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserInfo). - Equal(`$.result.user_id`, adminInfo.UserID). - Equal(`$.result.user_role`, float64(3)). - End(), - RespondStatus: http.StatusOK, + testTable := []test.APITable{ + { // incorrect method + Name: "test0_01", + Method: http.MethodGet, + Path: pathAuthRefresh, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPost, + Path: pathAuthRefresh, + StatusCode: 400, + Body: test.BodyInvalidArgument, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPost, + Path: pathAuthRefresh, + StatusCode: 400, + RequestBody: test.BodyTable{}, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": "Impossible to parse the key", + }, + RequestHeaders: adminHeader, }, - } - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Retrieval of user data", - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserInfo). - Equal(`$.result.user_id`, userInfo.UserID). - Equal(`$.result.user_role`, float64(1)). - End(), - RespondStatus: http.StatusOK, + { // ADMIN: request with empty token + Name: "test1_02", + Method: http.MethodPost, + Path: pathAuthRefresh, + StatusCode: 400, + RequestBody: test.BodyTable{ + "refresh_token": "", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": "Impossible to parse the key", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken token + Name: "test1_03", + Method: http.MethodPost, + Path: pathAuthRefresh, + StatusCode: 400, + RequestBody: test.BodyTable{ + "refresh": crypto.NewPassword(3, false), + }, + Body: test.BodyTable{ + "code": float64(400), + "result": "Impossible to parse the key", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_04", + Method: http.MethodPost, + Path: pathAuthRefresh, + StatusCode: 200, + RequestBody: test.BodyTable{ + "refresh": adminAuth.Tokens.Refresh, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Tokens", + "result.access_token": "*", + "result.refresh_token": "*", + }, + RequestHeaders: adminHeader, }, + { // ADMIN: request with an expired token + Name: "test1_05", + Method: http.MethodPost, + Path: pathAuthRefresh, + StatusCode: 400, + RequestBody: test.BodyTable{ + "refresh": fsutil.RemoveByteLineBreak(fsutil.MustReadFile("../../fixtures/auth/admin/expired_refresh_token")), + }, + Body: test.BodyInvalidArgument, + RequestHeaders: adminHeader, + }, + // TODO add other test cases to refresh token } - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Get("/auth/profile"). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -*/ diff --git a/api/auth/routes_test.go b/api/auth/routes_test.go new file mode 100644 index 00000000..e077ddb2 --- /dev/null +++ b/api/auth/routes_test.go @@ -0,0 +1,22 @@ +package auth + +import ( + "testing" + + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathAuth = "/auth" + pathAuthSignIn = pathAuth + "/signin" + pathAuthLogout = pathAuth + "/logout" + pathAuthRefresh = pathAuth + "/refresh" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T)) { + app, teardownTestCase := test.API(t) + New(app.Handler).Routes() + app.AddRoute404() + + return app, teardownTestCase +} diff --git a/api/event/event_test.go b/api/event/event_test.go index 7e95652b..012f5325 100644 --- a/api/event/event_test.go +++ b/api/event/event_test.go @@ -1,355 +1,318 @@ package event import ( - "bytes" - "encoding/json" - "io" "net/http" - "net/http/httptest" "testing" - "github.com/stretchr/testify/assert" - "github.com/werbot/werbot/internal/utils/test" - "github.com/werbot/werbot/pkg/maputil" + "github.com/werbot/werbot/pkg/crypto" ) -func TestHandler_getEvent(t *testing.T) { - app, teardownTestCase := test.API(t) - New(app.Handler).Routes() - app.AddRoute404() +func TestHandler_events(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) defer teardownTestCase(t) - adminInfo := app.GetUserInfo("admin@werbot.net", "admin@werbot.net") - userInfo := app.GetUserInfo("user@werbot.net", "user@werbot.net") - - testTable := []struct { - name string // The name of the test - method string // The HTTP method to use in our call - path string // The URL path that is being requested - statusCode int // The expected response status code - body map[string]any // The expected response body - requestBody map[string]any // The request body to sent with the request - requestHeaders map[string]string // The headers that are being set for the request - headers map[string]string // The response headers we want to test on - }{ - { - name: "unauthorized request", - method: http.MethodGet, - path: "/v1/event", - statusCode: 401, - body: test.BodyUnauthorized, + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathEvent, + StatusCode: 404, + Body: test.BodyNotFound, }, - { - name: "admin: request without parameters", - method: http.MethodGet, - path: "/v1/event", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: pathEvent, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, }, - { - name: "admin: error displaying list events with invalid arguments", - method: http.MethodGet, - path: "/v1/event/profile/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686?limit=abc", - statusCode: 400, - body: test.BodyInvalidArgument, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathEvent, "abc"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, }, - { - name: "admin: error displaying list events with fake name", - method: http.MethodGet, - path: "/v1/event/abc/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - statusCode: 400, - body: test.BodyInvalidArgument, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // ADMIN: error displaying list of events with a fake name + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathEvent, "abc", test.ConstAdminID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, }, - { - name: "admin: error displaying information about events with fake name", - method: http.MethodGet, - path: "/v1/event/abc/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686/59fab0fa-8f0a-4065-8863-0dae40166015", - statusCode: 400, - body: test.BodyInvalidArgument, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + + { // ADMIN: error displaying list of events with a broken user UUID + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathEvent, "abc", test.ConstAdminID) + "?user_id=" + crypto.NewPassword(8, false), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, }, // profile event - { - name: "admin: non-existent profile UUID", - method: http.MethodGet, - path: "/v1/event/profile/00000000-0000-0000-0000-000000000000", - statusCode: 404, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, + { // ADMIN: error displaying list of events due to invalid arguments, ignoring broken limit + Name: "test1_11", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstAdminID) + "?limit=abc", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.total": float64(2), }, + RequestHeaders: adminHeader, }, - { - name: "admin: list of all profile events", - method: http.MethodGet, - path: "/v1/event/profile/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.total": float64(2), - "result.records.0.id": "59fab0fa-8f0a-4065-8863-0dae40166015", - "result.records.1.id": "7c1bd7f9-2ef4-44c8-9756-0e85156ca58f", - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, + { // ADMIN: non-existent profile UUID + Name: "test1_12", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstFakeID), + StatusCode: 404, + RequestHeaders: adminHeader, + }, + { // ADMIN: broken profile UUID + Name: "test1_13", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, crypto.NewPassword(8, false)), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: list of all profile events + Name: "test1_14", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstAdminID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.total": float64(2), }, + RequestHeaders: adminHeader, }, - { - name: "admin: list of all profile events with limit", - method: http.MethodGet, - path: "/v1/event/profile/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686?limit=1", - statusCode: 200, - body: map[string]any{ + { // ADMIN: list of all profile events with limit + Name: "test1_15", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstAdminID) + "?limit=1", + StatusCode: 200, + Body: test.BodyTable{ "code": float64(200), "result.total": float64(2), - "result.records.0.id": "59fab0fa-8f0a-4065-8863-0dae40166015", "result.records.1.id": nil, }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + RequestHeaders: adminHeader, }, - { - name: "admin: profile event information by UUID", - method: http.MethodGet, - path: "/v1/event/profile/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686/59fab0fa-8f0a-4065-8863-0dae40166015", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.ip": "2001:db8:85a3::8a2e:370:7334", - "result.event": float64(1), - "result.meta_data": "e30=", - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // USER: error displaying profile events not owned by the user + Name: "test2_11", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstAdminID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, - { - name: "user: error displaying profile events not owned by the user", - method: http.MethodGet, - path: "/v1/event/profile/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + userInfo.Tokens.Access, + + // project event + { // ADMIN: non-existent project UUID + Name: "test1_11", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProject, test.ConstFakeID), + StatusCode: 404, + RequestHeaders: adminHeader, + }, + { // ADMIN: list of all project events + Name: "test1_22", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProject, test.ConstAdminEventProjectID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.total": float64(2), + "result.records.0.project_id": test.ConstAdminProjectEventID, + "result.records.1.project_id": "*", }, + RequestHeaders: adminHeader, }, - { - name: "user: error displaying profile event info not owned by the user", - method: http.MethodGet, - path: "/v1/event/profile/008feb1d-12f2-4bc3-97ff-c8d7fb9f7686/59fab0fa-8f0a-4065-8863-0dae40166015", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + userInfo.Tokens.Access, + { // ADMIN: list of all project events with limit + Name: "test1_23", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProject, test.ConstAdminEventProjectID) + "?limit=1", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.total": float64(2), + "result.records.0.project_id": test.ConstAdminProjectEventID, + "result.records.1.project_id": nil, }, + RequestHeaders: adminHeader, + }, + { // USER: error displaying project events not owned by the user + Name: "test2_21", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProject, test.ConstAdminEventProjectID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, - // project event - { - name: "admin: non-existent project UUID", - method: http.MethodGet, - path: "/v1/event/project/00000000-0000-0000-0000-000000000000", - statusCode: 404, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + // scheme event + { // ADMIN: non-existent scheme UUID + Name: "test1_31", + Method: http.MethodGet, + Path: test.PathGluing(pathEventScheme, test.ConstFakeID), + StatusCode: 404, + RequestHeaders: adminHeader, }, - { - name: "admin: list of all project events", - method: http.MethodGet, - path: "/v1/event/project/26060c68-5a06-4a57-b87a-be0f1e787157", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.total": float64(2), - "result.records.0.id": "163dee10-2a74-4436-9507-65a97a711ba8", - "result.records.1.id": "9758b5ee-367d-4a70-965b-14a129cca4d7", - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, + { // ADMIN: list of all scheme events + Name: "test1_32", + Method: http.MethodGet, + Path: test.PathGluing(pathEventScheme, test.ConstAdminEventSchemeID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.total": float64(11), + "result.records.0.session_id": "*", + "result.records.11.session_id": nil, }, + RequestHeaders: adminHeader, }, - { - name: "admin: list of all project events with limit", - method: http.MethodGet, - path: "/v1/event/project/26060c68-5a06-4a57-b87a-be0f1e787157?limit=1", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.total": float64(2), - "result.records.0.id": "163dee10-2a74-4436-9507-65a97a711ba8", - "result.records.1.id": nil, - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, + { // ADMIN: list of all scheme events with limit + Name: "test1_33", + Method: http.MethodGet, + Path: test.PathGluing(pathEventScheme, test.ConstAdminEventSchemeID) + "?limit=1", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.total": float64(11), + "result.records.0.session_id": "*", + "result.records.1.session_id": nil, }, + RequestHeaders: adminHeader, }, - { - name: "admin: project event information by UUID", - method: http.MethodGet, - path: "/v1/event/project/26060c68-5a06-4a57-b87a-be0f1e787157/163dee10-2a74-4436-9507-65a97a711ba8", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.ip": "192.168.0.1", - "result.event": float64(1), - "result.meta_data": "e30=", - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // USER: error displaying scheme events not owned by the user + Name: "test2_31", + Method: http.MethodGet, + Path: test.PathGluing(pathEventScheme, test.ConstAdminEventSchemeID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, - { - name: "user: error displaying project events not owned by the user", - method: http.MethodGet, - path: "/v1/event/project/26060c68-5a06-4a57-b87a-be0f1e787157", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + userInfo.Tokens.Access, - }, + // TODO add other test cases to show events from other categories + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_event(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathEvent, + StatusCode: 404, + Body: test.BodyNotFound, }, - { - name: "user: error displaying project event info not owned by the user", - method: http.MethodGet, - path: "/v1/event/project/26060c68-5a06-4a57-b87a-be0f1e787157/163dee10-2a74-4436-9507-65a97a711ba8", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + userInfo.Tokens.Access, - }, + { // ADMIN: error displaying information about events with fake name + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathEvent, "abc", test.ConstAdminID, test.ConstAdminProfileEventID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, }, - // server event - { - name: "admin: non-existent server UUID", - method: http.MethodGet, - path: "/v1/event/server/00000000-0000-0000-0000-000000000000", - statusCode: 404, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, + // profile event + { // ADMIN: profile event information by UUID + Name: "test1_11", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstAdminID, test.ConstAdminProfileEventID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.user_id": test.ConstAdminID, + "result.profile_id": test.ConstAdminProfileEventID, + "result.event": float64(9), + "result.ip": "2001:db8:85a3::8a2e:370:7334", + "result.meta_data": "e30=", + "result.section": float64(1), + "result.session_id": "98e3ddfc-dab0-4d4e-b48e-ab1717acae8b", + "result.user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:35.0) Gecko/20100101 Firefox/35.", + "result.created_at": "*", }, + RequestHeaders: adminHeader, }, - { - name: "admin: list of all server events", - method: http.MethodGet, - path: "/v1/event/server/0c3a8869-6fc0-4666-bf60-15475473392a", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.total": float64(11), - "result.records.0.id": "dea438b3-ca64-45ad-80a6-51275730f078", - "result.records.1.id": "a2ef053e-4124-487b-9e90-b8f249d49807", - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // USER: error displaying profile event info not owned by the user + Name: "test2_11", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProfile, test.ConstAdminID, test.ConstAdminProfileEventID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, - { - name: "admin: list of all server events with limit", - method: http.MethodGet, - path: "/v1/event/server/0c3a8869-6fc0-4666-bf60-15475473392a?limit=1", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.total": float64(11), - "result.records.0.id": "dea438b3-ca64-45ad-80a6-51275730f078", - "result.records.1.id": nil, - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, + + // project event + { // ADMIN: project event information by UUID + Name: "test1_21", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProject, test.ConstAdminEventProjectID, test.ConstAdminProjectEventID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.user_id": test.ConstAdminID, + "result.project_id": test.ConstAdminEventProjectID, + "result.event": float64(1), + "result.ip": "192.168.0.1", + "result.meta_data": "e30=", + "result.section": float64(1), + "result.session_id": "98e3ddfc-dab0-4d4e-b48e-ab1717acae8b", + "result.user_agent": "Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; KFJWI Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.68 like Chrome/39.0.2171.93 Safari/537.36", + "result.created_at": "*", }, + RequestHeaders: adminHeader, }, - { - name: "admin: server event information by UUID", - method: http.MethodGet, - path: "/v1/event/server/0c3a8869-6fc0-4666-bf60-15475473392a/dea438b3-ca64-45ad-80a6-51275730f078", - statusCode: 200, - body: map[string]any{ - "code": float64(200), - "result.ip": "192.168.1.1", - "result.event": float64(1), - "result.meta_data": "e30=", - }, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + adminInfo.Tokens.Access, - }, + { // USER: error displaying project event info not owned by the user + Name: "test2_21", + Method: http.MethodGet, + Path: test.PathGluing(pathEventProject, test.ConstAdminEventProjectID, test.ConstAdminProjectEventID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, - { - name: "user: error displaying server events not owned by the user", - method: http.MethodGet, - path: "/v1/event/server/0c3a8869-6fc0-4666-bf60-15475473392a", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + userInfo.Tokens.Access, + + // scheme event + { // ADMIN: scheme event information by UUID + Name: "test1_31", + Method: http.MethodGet, + Path: test.PathGluing(pathEventScheme, test.ConstAdminEventSchemeID, test.ConstAdminSchemeEventID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "result.user_id": test.ConstAdminID, + "result.scheme_id": test.ConstAdminEventSchemeID, + "result.event": float64(1), + "result.ip": "192.168.1.1", + "result.meta_data": "e30=", + "result.section": float64(1), + "result.session_id": "98e3ddfc-dab0-4d4e-b48e-ab1717acae8b", + "result.user_agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; LCJB; rv:11.0) like Gecko", + "result.created_at": "*", }, + RequestHeaders: adminHeader, }, - { - name: "user: error displaying server event info not owned by the user", - method: http.MethodGet, - path: "/v1/event/server/0c3a8869-6fc0-4666-bf60-15475473392a/dea438b3-ca64-45ad-80a6-51275730f078", - statusCode: 404, - body: test.BodyNotFound, - requestHeaders: map[string]string{ - `Authorization`: `Bearer ` + userInfo.Tokens.Access, - }, + { // USER: error displaying scheme event info not owned by the user + Name: "test2_31", + Method: http.MethodGet, + Path: test.PathGluing(pathEventScheme, test.ConstAdminEventSchemeID, test.ConstAdminSchemeEventID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, + // TODO add other test cases to show event information from other categories } - for _, tc := range testTable { - t.Run(tc.name, func(t *testing.T) { - // Create and send request - rbody, _ := json.Marshal(tc.requestBody) - request := httptest.NewRequest(tc.method, tc.path, bytes.NewReader(rbody)) - request.Header.Add(`Content-Type`, `application/json`) - - // Request Headers - for k, v := range tc.requestHeaders { - request.Header.Add(k, v) - } - - response, _ := app.App.Test(request) - - // Status Code - statusCode := response.StatusCode - if statusCode != tc.statusCode { - assert.Equal(t, statusCode, tc.statusCode) - } - - // Headers - for k, want := range tc.headers { - headerValue := response.Header.Get(k) - if headerValue != want { - assert.Equal(t, headerValue, want, "Response header '"+k+"' was incorrect") - } - } - - // Response Body - if len(tc.body) > 0 { - body, _ := io.ReadAll(response.Body) - var resp map[string]any - json.Unmarshal(body, &resp) - for key, want := range tc.body { - val, _ := maputil.GetByPath(key, resp) - if val != want { - assert.Equal(t, val, want, "Body key ["+key+"] was incorrect") - } - } - } - }) - } + test.RunCaseAPITests(t, app, testTable) } diff --git a/api/event/routes_test.go b/api/event/routes_test.go new file mode 100644 index 00000000..27cb541f --- /dev/null +++ b/api/event/routes_test.go @@ -0,0 +1,26 @@ +package event + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathEvent = "/v1/event" + pathEventProfile = pathEvent + "/profile" + pathEventProject = pathEvent + "/project" + pathEventScheme = pathEvent + "/scheme" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/key/key_test.go b/api/key/key_test.go index 2de22956..5eb4cb7c 100644 --- a/api/key/key_test.go +++ b/api/key/key_test.go @@ -1,887 +1,683 @@ package key -/* import ( - "context" - "encoding/json" "net/http" "testing" - "time" - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - accountpb "github.com/werbot/werbot/api/proto/account" - keypb "github.com/werbot/werbot/api/proto/key" - "github.com/werbot/werbot/api" - "github.com/werbot/werbot/api/auth" - "github.com/werbot/werbot/internal" - "github.com/werbot/werbot/internal/crypto" - "github.com/werbot/werbot/internal/tests" - "github.com/werbot/werbot/internal/web/middleware" -) - -var ( - testHandler *tests.TestHandler - adminInfo *tests.UserInfo - userInfo *tests.UserInfo + "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/crypto" + "github.com/werbot/werbot/pkg/utils/fsutil" ) -func init() { - testHandler = tests.InitTestServer("../../../.env") - auth.New(&web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Cache: testHandler.Cache, - Auth: *testHandler.Auth, - }).Routes() - authMiddleware := middleware.Auth(testHandler.Cache).Execute() - webHandler := &web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Auth: authMiddleware, +func TestHandler_generateNewKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathKeysGenerate, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: generate new key + Name: "test1_01", + Method: http.MethodGet, + Path: pathKeysGenerate, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "New ssh key", + "result.finger_print": "*", + "result.key_type": float64(1), + "result.public": "*", + "result.uuid": "*", + "result.passphrase": nil, + }, + RequestHeaders: adminHeader, + }, + { // USER: generate new key + Name: "test2_01", + Method: http.MethodGet, + Path: pathKeysGenerate, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "New ssh key", + "result.finger_print": "*", + "result.key_type": float64(1), + "result.public": "*", + "result.uuid": "*", + "result.passphrase": nil, + }, + RequestHeaders: userHeader, + }, + // TODO add other test cases to generate new key } - New(webHandler).Routes() // add test module handler - testHandler.FinishHandler() // init finale handler for apitest - - adminInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-admin@werbot.net", - Password: "test-admin@werbot.net", - }) - - userInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-user@werbot.net", - Password: "test-user@werbot.net", - }) -} - -func apiTest() *apitest.APITest { - return apitest.New(). - //Debug(). - HandlerFunc(testHandler.Handler) -} -func newKey() string { - key, err := crypto.NewSSHKey("KEY_TYPE_ED25519") - if err != nil { - return crypto.MsgFailedCreatingSSHKey - } - return string(key.PublicKey) + test.RunCaseAPITests(t, app, testTable) } -func Test_getKey(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} - - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - { - Name: "User keys your user_id", - RequestParam: map[string]string{ - "user_id": adminInfo.UserID, - }, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - { - Name: "Send your key_id", // for user test-admin@werbot.net - RequestParam: map[string]string{ - "key_id": adminInfo.UserID, - }, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - } - - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserKeys). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "User keys your user_id", // for user test-admin@werbot.net - RequestParam: map[string]string{ - "user_id": adminInfo.UserID, - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserKeys). - Equal(`$.result.total`, float64(3)). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Send your key_id", // for user test-admin@werbot.net - RequestParam: map[string]string{ - "key_id": "d8ac2125-1770-4fd5-94a8-b5d83cde47aa", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyInfo). - Equal(`$.result.user_id`, adminInfo.UserID). - Equal(`$.result.title`, "test_key 1"). - Equal(`$.result.fingerprint`, "fb:22:c9:13:5f:37:09:14:26:f0:84:9b:35:fd:a7:ba"). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "All keys another user_id", // for user test-user@werbot.net - RequestParam: map[string]string{ - "user_id": userInfo.UserID, - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserKeys). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Show key information by another user_id", // for user test-admin@werbot.net - RequestParam: map[string]string{ - "key_id": "1a57bee5-1dca-4965-b6c2-bc60ba5526af", - "user_id": adminInfo.UserID, - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "Send non-existent user_id", - RequestParam: map[string]string{ - "user_id": "00000000-0000-0000-0000-000000000000", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "Send non-existent key_id", - RequestParam: map[string]string{ - "key_id": "00000000-0000-0000-0000-000000000000", - "user_id": "e9a1f437-8f32-4463-9f89-a886a623febc", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "Invalid user_id parameter", - RequestParam: map[string]string{ - "user_id": "00000000-0000", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - Equal(`$.result.userid`, "userId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Invalid key_id parameter", - RequestParam: map[string]string{ - "key_id": "00000000-0000", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - Equal(`$.result.keyid`, "keyId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Invalid key_id and user_id parameter", - RequestParam: map[string]string{ - "key_id": "00000000-0000", - "user_id": "00000000-0000", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - Equal(`$.result.userid`, "userId must be a valid UUID"). - Equal(`$.result.keyid`, "keyId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - } - - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserKeys). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Send your user_id", // for user test-user@werbot.net - RequestParam: map[string]string{ - "user_id": userInfo.UserID, - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserKeys). - Equal(`$.result.total`, float64(2)). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Send another user_id", // for user test-admin@werbot.net, this parameters ignoring for this roles - RequestParam: map[string]string{ - "user_id": adminInfo.UserID, - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgUserKeys). - Equal(`$.result.total`, float64(2)). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Invalid user_id parameter", - RequestParam: map[string]string{ - "user_id": "00000000-0000", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - Equal(`$.result.userid`, "userId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Invalid key_id parameter", - RequestParam: map[string]string{ - "key_id": "00000000-0000", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - Equal(`$.result.keyid`, "keyId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Invalid key_id and user_id parameter", - RequestParam: map[string]string{ - "key_id": "00000000-0000", - "user_id": "00000000-0000", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - Equal(`$.result.userid`, "userId must be a valid UUID"). - Equal(`$.result.keyid`, "keyId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, +func TestHandler_keys(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathKeys, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: pathKeys, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(12), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with pagination parameters + Name: "test1_02", + Method: http.MethodGet, + Path: pathKeys + "?limit=2&offset=0", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(12), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with incorrect user UUID parameter + Name: "test1_03", + Method: http.MethodGet, + Path: pathKeys + "?user_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken user UUID parameter + Name: "test1_04", + Method: http.MethodGet, + Path: pathKeys + "?user_id=" + crypto.NewPassword(8, false), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(12), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with pagination and valid user UUID parameters + Name: "test1_05", + Method: http.MethodGet, + Path: pathKeys + "?limit=2&offset=0&user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(2), + "result.public_keys.0.fingerprint": "*", + "result.public_keys.0.key": "*", + "result.public_keys.0.key_id": "*", + "result.public_keys.0.user_id": "*", + "result.public_keys.0.title": "*", + "result.public_keys.0.locked_at": nil, + "result.public_keys.0.archived_at": nil, + "result.public_keys.0.updated_at": nil, + "result.public_keys.0.created_at": "*", + "result.public_keys.1.fingerprint": "*", + "result.public_keys.1.key": "*", + "result.public_keys.1.key_id": "*", + "result.public_keys.1.user_id": "*", + "result.public_keys.1.title": "*", + "result.public_keys.1.locked_at": "*", + "result.public_keys.1.archived_at": nil, + "result.public_keys.1.updated_at": "*", + "result.public_keys.1.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with valid user UUID parameter + Name: "test1_06", + Method: http.MethodGet, + Path: pathKeys + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(2), + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: pathKeys + "?limit=1&offset=0", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(1), + "result.public_keys.0.fingerprint": "*", + "result.public_keys.0.key": nil, + "result.public_keys.0.key_id": "*", + "result.public_keys.0.user_id": nil, + "result.public_keys.0.title": "*", + "result.public_keys.0.locked_at": nil, + "result.public_keys.0.archived_at": nil, + "result.public_keys.0.updated_at": nil, + "result.public_keys.0.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: request with valid user UUID parameter + Name: "test2_02", + Method: http.MethodGet, + Path: pathKeys + "?user_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Keys", + "result.total": float64(1), + "result.public_keys.0.fingerprint": "*", + "result.public_keys.0.key": nil, + "result.public_keys.0.key_id": "*", + "result.public_keys.0.user_id": nil, + "result.public_keys.0.title": "*", + "result.public_keys.0.locked_at": nil, + "result.public_keys.0.archived_at": nil, + "result.public_keys.0.updated_at": nil, + "result.public_keys.0.created_at": "*", + }, + RequestHeaders: userHeader, }, } - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Get("/v1/keys"). - QueryParams(tc.RequestParam.(map[string]string)). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -func Test_addKey(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} - - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: keypb.AddKey_Request{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - } - - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: keypb.AddKey_Request{}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Add key by your user_id", // for user test-admin@werbot.net - RequestBody: keypb.AddKey_Request{ - UserId: adminInfo.UserID, - Key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFQmBo7P94hOf00dl3DKfYNcLz2Sd1WRs6SHZE6rFQlx", - Title: "test1", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyAdded). - End(), - RespondStatus: http.StatusOK, +func TestHandler_key(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with broken key UUID parameter + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, crypto.NewPassword(8, false)), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with key UUID parameter + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key", + "result.fingerprint": "*", + "result.key": "*", + "result.key_id": "*", + "result.user_id": test.ConstAdminID, + "result.title": "public_key 1", + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with key UUID and user UUID parameter + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID) + "?user_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with key UUID and user UUID parameter + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstUserKeyID1) + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key", + "result.title": "public_key 4", + "result.fingerprint": "*", + "result.key": "*", + "result.key_id": "*", + "result.user_id": test.ConstUserID, + "result.locked_at": "*", + "result.archived_at": nil, + "result.updated_at": "*", + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with key UUID parameter + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstUserKeyID2), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key", + "result.fingerprint": "*", + "result.key": nil, + "result.key_id": "*", + "result.user_id": nil, + "result.title": "public_key 5", + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: request with key UUID and user UUID parameter + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request key UUID and user UUID parameter + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID) + "?user_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, } - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: keypb.AddKey_Request{}, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Adding a key to your profile", - RequestBody: keypb.AddKey_Request{ - Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCPl/FmQtusakH1dqqB2jwbZ5gI0BEhjpLsSx/NfnjF+6Nmd1+lk533pyDod3KJYBzr/TjgOLp7jTLw+GcrczjqBLboUSXb564eokApOSrEBvko/MGtcIaJ5RGtenljPtHgbt3N/ldeiGXgUfImpDkYDXY9RpG5d0CN7YtgouIqIQ==", - Title: "test1", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyAdded). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Add key for another user_id", // for user test-admin@werbot.net, this parameters ignoring for this roles - RequestBody: keypb.AddKey_Request{ - UserId: adminInfo.UserID, - Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCPl/FmQtusakH1dqqB2jwbZ5gI0BEhjpLsSx/NfnjF+6Nmd1+lk533pyDod3KJYBzr/TjgOLp7jTLw+GcrczjqBLboUSXb564eokApOSrEBvko/MGtcIaJ5RGtenljPtHgbt3N/ldeiGXgUfImpDkYDXY9RpG5d0CN7YtgouIqIQ==", - Title: "test1", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyAdded). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Invalid key parameter", - RequestBody: keypb.AddKey_Request{ - Key: "ssh-rsa AsSx/NfnjF+OSrEBveiGXgUfImpDkYDXY9RpG5d0CN7YtgouIqIQ==", - Title: "test1", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "The public key has a broken structure"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Invalid title parameter", - RequestBody: keypb.AddKey_Request{ - Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCPl/FmQtusakH1dqqB2jwbZ5gI0BEhjpLsSx/NfnjF+6Nmd1+lk533pyDod3KJYBzr/TjgOLp7jTLw+GcrczjqBLboUSXb564eokApOSrEBvko/MGtcIaJ5RGtenljPtHgbt3N/ldeiGXgUfImpDkYDXY9RpG5d0CN7YtgouIqIQ==", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.title`, "Title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Use another user_id when adding a new key", - RequestBody: keypb.AddKey_Request{ - UserId: adminInfo.UserID, - Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCPl/FmQtusakH1dqqB2jwbZ5gI0BEhjpLsSx/NfnjF+6Nmd1+lk533pyDod3KJYBzr/TjgOLp7jTLw+GcrczjqBLboUSXb564eokApOSrEBvko/MGtcIaJ5RGtenljPtHgbt3N/ldeiGXgUfImpDkYDXY9RpG5d0CN7YtgouIqIQ==", - Title: "test1", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyAdded). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Object already exists", - RequestBody: keypb.AddKey_Request{ - Key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWl2aY8FicEWNAlrQ+DwmhonSuhU8SsXJErdO9WpPKN", - Title: "test1", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "Object already exists"). - End(), - RespondStatus: http.StatusBadRequest, - }, - } - - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - resp := apiTest(). - Post("/v1/keys"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - - // delete added project - data := map[string]keypb.AddKey_Response{} - json.NewDecoder(resp.Response.Body).Decode(&data) - if data["result"].KeyId != "" { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - rClient := keypb.NewKeyHandlersClient(testHandler.GRPC.Client) - rClient.DeleteKey(ctx, &keypb.DeleteKey_Request{ - UserId: tc.RequestUser.UserID, - KeyId: data["result"].KeyId, - }) - } - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -func Test_patchKey(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} - - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: keypb.AddKey_Request{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, +func TestHandler_addKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.key": "value is required", + "result.title": "value is required", + }, + RequestHeaders: adminHeader, + }, + + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "ab", + "key": "abc", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value length must be at least 3 characters", + "result.key": "value length must be at least 70 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request adding a key to ADMIN profile + Name: "test1_03", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "Test key", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user1/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key added", + "result.fingerprint": "6e:cc:de:6c:a7:65:84:9e:7f:32:e3:5a:0b:82:27:89", + "result.key_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request a repeating key + Name: "test1_04", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 409, + RequestBody: test.BodyTable{ + "title": "Test key", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user1/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(409), + "message": "Conflict", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request adding a key to another user by user UUID + Name: "test1_05", + Method: http.MethodPost, + Path: pathKeys + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "Test key", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user1/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key added", + "result.fingerprint": "6e:cc:de:6c:a7:65:84:9e:7f:32:e3:5a:0b:82:27:89", + "result.key_id": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request a repeating key (the key was added by the admin earlier) + // the test depends on the test "ADMIN: Authorized request adding a key to another user by user UUID" + Name: "test2_01", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 409, + RequestBody: test.BodyTable{ + "title": "Test key", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user1/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(409), + "message": "Conflict", + }, + RequestHeaders: userHeader, + }, + { // USER: request adding a key + Name: "test2_02", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "Test key2", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user2/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key added", + "result.fingerprint": "bd:e6:3a:03:9f:29:7a:9c:fa:d0:f5:63:aa:16:a6:46", + "result.key_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: request with valid user UUID and new key + // The key will be added to the USER profile. + Name: "test2_03", + Method: http.MethodPost, + Path: pathKeys + "?user_id=" + test.ConstAdminID, + StatusCode: 409, + RequestBody: test.BodyTable{ + "title": "Test key", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user1/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(409), + "message": "Conflict", + }, + RequestHeaders: userHeader, + }, + { // USER: request with valid user UUID and double key + // The key will be added to the USER profile. + Name: "test2_04", + Method: http.MethodPost, + Path: pathKeys, + StatusCode: 409, + RequestBody: test.BodyTable{ + "user_id": test.ConstAdminID, + "title": "Test key", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user1/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(409), + "message": "Conflict", + }, + RequestHeaders: userHeader, + }, + { // USER: request adding a key to another user by user UUID (ignored) + Name: "test2_05", + Method: http.MethodPost, + Path: pathKeys + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "Test key2", + "key": string(fsutil.MustReadFile("../../fixtures/keys/users/user3/id_ed25519.pub")), + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key added", + "result.fingerprint": "a2:e8:70:60:58:28:85:ba:d8:b6:eb:88:f0:00:20:7a", + "result.key_id": "*", + }, + RequestHeaders: userHeader, }, } - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestBody: keypb.UpdateKey_Request{}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.key`, "key is a required field"). - Equal(`$.result.keyid`, "keyId is a required field"). - Equal(`$.result.title`, "title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Parameter key is filled", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "6437da7e-c9a4-463d-8b4d-2a7d1f730875", - Key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWl2aY8FicEWNAlrQ+DwmhonSuhU8SsXJErdO9WpPKN", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.title`, "title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Key has already been added", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "6437da7e-c9a4-463d-8b4d-2a7d1f730875", - Key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWl2aY8FicEWNAlrQ+DwmhonSuhU8SsXJErdO9WpPKN", - Title: "new title", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "object already exists"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "Key update and description for user with user_id", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "2511bbbe-c8d2-4e79-9e89-7e8f2b366a57", - Key: newKey(), - Title: "new title", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyUpdated). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "The public key has a broken structure", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "6437da7e-c9a4-463d-8b4d-2a7d1f730875", - Key: "ssh-ed25519 NzaC1lZDI1NTE5Wl2aY8FicEWNAlrQSuhU8SsXJErdO9WpPKN", - Title: "new title", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "the public key has a broken structure"). - End(), - RespondStatus: http.StatusBadRequest, - }, - } - - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Update key", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "abe03b06-834b-4e35-a3f6-7e86df525c81", - Key: newKey(), - Title: "new title", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyUpdated). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Updated key and description, ignoring someone else's user_id", - RequestBody: keypb.UpdateKey_Request{ - UserId: "0b792872-174a-4da4-9efa-f3fac872314e", - KeyId: "abe03b06-834b-4e35-a3f6-7e86df525c81", - Key: newKey(), - Title: "new title", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyUpdated). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Unsuccessful renewal of a key that did not belong to an authorized user", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "2511bbbe-c8d2-4e79-9e89-7e8f2b366a57", - Key: newKey(), - Title: "new title", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "The public key has a broken structure", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "abe03b06-834b-4e35-a3f6-7e86df525c81", - Key: "ssh-ed25519 NzaC1lZDI1NTE5Wl2aY8FicEWNAlrQSuhU8SsXJErdO9WpPKN", - Title: "new title", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, "the public key has a broken structure"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "The wrong parameter Key_id in the request", - RequestBody: keypb.UpdateKey_Request{ - KeyId: "00000000-0000", - UserId: "00000000-0000", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.key`, "key is a required field"). - Equal(`$.result.keyid`, "keyId must be a valid UUID"). - Equal(`$.result.title`, "title is a required field"). - Equal(`$.result.userid`, "userId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - } - - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Patch("/v1/keys"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -func TestHandler_deleteKey(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} - - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - } - - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Deletion of your key", - RequestParam: map[string]string{ - "user_id": adminInfo.UserID, - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyRemoved). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Deleting another user's key", - RequestParam: map[string]string{ - "user_id": userInfo.UserID, - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyRemoved). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "The wrong parameter key_id in the request", - RequestParam: map[string]string{ - "key_id": "00000000-0000", - "user_id": "00000000-0000", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - End(), - RespondStatus: http.StatusBadRequest, - }, - } - - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Deletion of your key", - RequestParam: map[string]string{ - "user_id": userInfo.UserID, - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgKeyRemoved). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "Attempt to delete someone else's key", - RequestParam: map[string]string{ - "key_id": "2511bbbe-c8d2-4e79-9e89-7e8f2b366a57", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "Invalid key_id parameter", - RequestParam: map[string]string{ - "key_id": "00000000-0000", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateParams). - End(), - RespondStatus: http.StatusBadRequest, +func TestHandler_updateKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: pathKeys, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPatch, + Path: pathKeys, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameter + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameter + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "ab", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with parameters + Name: "test1_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "test key name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with parameters to another user by user UUID + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathKeys, test.ConstUserKeyID1) + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "test key name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key updated", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with parameters and outsider key UUID + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "test key name", + }, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with parameters and outsider key UUID and user UUID + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID) + "?user_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "test key name", + }, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - rClient := keypb.NewKeyHandlersClient(testHandler.GRPC.Client) - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - reqBody := tc.RequestParam.(map[string]string) - - if reqBody["user_id"] != "" { - publicKey, _ := rClient.AddKey(ctx, &keypb.AddKey_Request{ - UserId: reqBody["user_id"], - Title: "new test title", - Key: newKey(), - }) - reqBody["key_id"] = publicKey.GetKeyId() - } - - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Delete("/v1/keys"). - QueryParams(reqBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -func TestHandler_getGenerateNewKey(t *testing.T) { - t.Parallel() - testCases := map[string][]tests.TestCase{} - - testCases["ROLE_USER_UNSPECIFIED"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - } - - testCases["ROLE_ADMIN"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgSSHKeyCreated). - Equal(`$.result.key_type`, "KEY_TYPE_ED25519"). - End(), - RespondStatus: http.StatusOK, - }, - } - - testCases["ROLE_USER"] = []tests.TestCase{ - { - Name: "Without parameters", - RequestParam: map[string]string{}, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgSSHKeyCreated). - Equal(`$.result.key_type`, "KEY_TYPE_ED25519"). - End(), - RespondStatus: http.StatusOK, +func TestHandler_deleteKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: pathKeys, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodDelete, + Path: pathKeys, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key removed", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: authorized request other USER + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathKeys, test.ConstUserKeyID1), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request other USER with user UUID + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathKeys, test.ConstUserKeyID1) + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key removed", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathKeys, test.ConstUserKeyID1), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Key removed", + }, + RequestHeaders: userHeader, + }, + { // USER: request other USER + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request other USER with user UUID + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathKeys, test.ConstAdminKeyID) + "?user_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, }, } - for role, rtc := range testCases { - t.Run(role, func(t *testing.T) { - for _, tc := range rtc { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Get("/v1/keys/generate"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } - }) - } + test.RunCaseAPITests(t, app, testTable) } -*/ diff --git a/api/key/routes_test.go b/api/key/routes_test.go new file mode 100644 index 00000000..14f0bbed --- /dev/null +++ b/api/key/routes_test.go @@ -0,0 +1,24 @@ +package key + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathKeys = "/v1/keys" + pathKeysGenerate = pathKeys + "/generate" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/license/license_test.go b/api/license/license_test.go index 3856df2c..a70e4863 100644 --- a/api/license/license_test.go +++ b/api/license/license_test.go @@ -1,109 +1,118 @@ package license -/* import ( "net/http" "testing" - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - accountpb "github.com/werbot/werbot/api/proto/account" - "github.com/werbot/werbot/api" - "github.com/werbot/werbot/api/auth" - "github.com/werbot/werbot/internal" - "github.com/werbot/werbot/internal/tests" - "github.com/werbot/werbot/internal/web/middleware" + "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/utils/fsutil" ) -var ( - testHandler *tests.TestHandler - adminInfo *tests.UserInfo - userInfo *tests.UserInfo -) +func TestHandler_licenseInfo(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) -func init() { - testHandler = tests.InitTestServer("../../../.env") - auth.New(&web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Cache: testHandler.Cache, - Auth: *testHandler.Auth, - }).Routes() - authMiddleware := middleware.Auth(testHandler.Cache).Execute() - webHandler := &web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Auth: authMiddleware, + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathLicenseInfo, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: license info + Name: "test1_01", + Method: http.MethodGet, + Path: pathLicenseInfo, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "License", + "result.customer": "Mr. Robot", + "result.expired": true, + "result.expires_at": "*", + "result.issued": "free", + "result.issued_at": "*", + "result.limits.Companies": float64(99), + "result.limits.Servers": float64(99), + "result.limits.Users": float64(99), + "result.modules.0": "module1", + "result.modules.1": "module2", + "result.modules.2": "module3", + }, + RequestHeaders: adminHeader, + }, + { // USER: license info + Name: "test2_01", + Method: http.MethodGet, + Path: pathLicenseInfo, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, } - New(webHandler, internal.GetString("LICENSE_KEY_PUBLIC", "")).Routes() // add test module handler - testHandler.FinishHandler() // init finale handler for apitest + test.RunCaseAPITests(t, app, testTable) +} - adminInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-admin@werbot.net", - Password: "test-admin@werbot.net", - }) +func TestHandler_licenseInfo_ee(t *testing.T) { + app, teardownTestCase, adminHeader, _ := setupTest(t) + defer teardownTestCase(t) - adminInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-user@werbot.net", - Password: "test-user@werbot.net", - }) -} + pubKeyOk := string(fsutil.MustReadFile("../../fixtures/licenses/publicKey_ok.key")) + t.Setenv("LICENSE_KEY_PUBLIC", pubKeyOk) + t.Setenv("LICENSE_FILE", "../../fixtures/licenses/license_ok.key") -func apiTest() *apitest.APITest { - return apitest.New(). - //Debug(). - HandlerFunc(testHandler.Handler) + testTable := []test.APITable{ + { // ADMIN: EE license info + Name: "test1_01", + Method: http.MethodGet, + Path: pathLicenseInfo, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "License", + "result.customer": "8ED96811-1804-4A13-9CE7-05874869A1CF", + "result.expires_at": "*", + "result.issued": "Werbot, Inc.", + "result.issued_at": "*", + "result.subscriber": "EED1CA19-4DC5-4376-83F5-61077B501961", + "result.type": "Enterprise", + "result.limits.Companies": float64(99), + "result.limits.Servers": float64(99), + "result.limits.Users": float64(99), + "result.modules.0": "module1", + "result.modules.1": "module2", + "result.modules.2": "module3", + }, + RequestHeaders: adminHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) } -func TestHandler_getLicenseInfo(t *testing.T) { - t.Parallel() +func TestHandler_licenseInfo_ee_broken(t *testing.T) { + app, teardownTestCase, adminHeader, _ := setupTest(t) + defer teardownTestCase(t) - testCases := []tests.TestCase{ - // Unauthorized user - { - Name: "getLicenseInfo_01", - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - // ROLE_ADMIN - Authorized admin - { - Name: "ROLE_ADMIN_getLicenseInfo_01", - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgLicenseInfo). - End(), - RespondStatus: http.StatusOK, - }, - // ROLE_USER - Authorized user - { - Name: "ROLE_USER_getLicenseInfo_01", - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, + t.Setenv("LICENSE_FILE", "../../fixtures/licenses/license_exp.key") + t.Setenv("LICENSE_KEY_PUBLIC", "../../fixtures/licenses/publicKey_ok.key") + + testTable := []test.APITable{ + { // ADMIN: license info + Name: "test1_01", + Method: http.MethodGet, + Path: pathLicenseInfo, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "The license key has a broken", + }, + RequestHeaders: adminHeader, }, } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - HandlerFunc(testHandler.Handler). - Get("/v1/license/info"). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } + test.RunCaseAPITests(t, app, testTable) } -*/ diff --git a/api/license/routes_test.go b/api/license/routes_test.go new file mode 100644 index 00000000..cd91d54f --- /dev/null +++ b/api/license/routes_test.go @@ -0,0 +1,24 @@ +package license + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathLicense = "/v1/license" + pathLicenseInfo = pathLicense + "/info" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler, "../../fixtures/licenses/publicKey_ok.key").Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/member/project_test.go b/api/member/project_test.go index aa2a9db4..4a09cb12 100644 --- a/api/member/project_test.go +++ b/api/member/project_test.go @@ -1,139 +1,1553 @@ package member -/* import ( "net/http" "testing" - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - accountpb "github.com/werbot/werbot/api/proto/account" - "github.com/werbot/werbot/api" - "github.com/werbot/werbot/api/auth" - "github.com/werbot/werbot/internal" - "github.com/werbot/werbot/internal/tests" - "github.com/werbot/werbot/internal/web/middleware" + "github.com/werbot/werbot/internal/trace" + "github.com/werbot/werbot/internal/utils/test" ) -var ( - testHandler *tests.TestHandler - adminInfo *tests.UserInfo - userInfo *tests.UserInfo -) +func TestHandler_projectMembers(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) -func init() { - testHandler = tests.InitTestServer("../../../.env") - auth.New(&web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Cache: testHandler.Cache, - Auth: *testHandler.Auth, - }).Routes() - authMiddleware := middleware.Auth(testHandler.Cache).Execute() - webHandler := &web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Auth: authMiddleware, + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathMembersProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: broken project UUID + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, "test"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: fake project UUID + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(7), + "result.members.0.member_id": "455b8913-c71d-4536-9b03-70bcb487b7cb", + "result.members.0.owner_id": test.ConstAdminID, + "result.members.0.owner_name": "Penny", + "result.members.0.project_id": test.ConstAdminProject1ID, + "result.members.0.project_name": "project1", + "result.members.0.role": float64(1), + "result.members.0.user_id": "68bf07a3-0132-4709-920b-5054f9eaa89a", + "result.members.0.user_name": "Carla", + //"result.members.0.updated_at": "*", + "result.members.0.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(12), + // ------------------------------- + "result.members.0.active": true, + "result.members.0.member_id": "4fc69519-b683-46f0-860c-3e7f12a17563", + "result.members.0.online": nil, + "result.members.0.owner_id": test.ConstUserID, + "result.members.0.owner_name": "Carly", + "result.members.0.project_id": test.ConstUserProject1ID, + "result.members.0.project_name": "project3", + "result.members.0.role": float64(1), + "result.members.0.schemes_count": float64(16), + "result.members.0.user_id": "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + "result.members.0.user_name": "Penny", + "result.members.0.created_at": "*", + // ------------------------------- + "result.members.1.active": true, + "result.members.1.member_id": "49a10a09-0bb3-48af-99cb-181533692585", + "result.members.1.owner_id": test.ConstUserID, + "result.members.1.owner_name": "Carly", + "result.members.1.project_id": test.ConstUserProject1ID, + "result.members.1.project_name": "project3", + "result.members.1.role": float64(1), + "result.members.1.schemes_count": float64(1), + "result.members.1.user_id": "b3dc36e2-7f84-414b-b147-7ac850369518", + "result.members.1.user_name": "Harrison", + "result.members.1.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID) + "?limit=1&owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(12), + "result.members.0.active": true, + "result.members.0.member_id": "49a10a09-0bb3-48af-99cb-181533692585", + "result.members.0.online": true, + "result.members.0.owner_id": test.ConstUserID, + "result.members.0.owner_name": "Carly", + "result.members.0.project_id": test.ConstUserProject1ID, + "result.members.0.project_name": "project3", + "result.members.0.role": float64(1), + "result.members.0.schemes_count": float64(1), + "result.members.0.user_id": "b3dc36e2-7f84-414b-b147-7ac850369518", + "result.members.0.user_name": "Harrison", + "result.members.0.created_at": "*", + "result.members.1.active": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: search users without project + Name: "test1_08", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, "search"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Users without project", + "result.total": float64(15), + "result.users.0.email": test.ConstAdminEmail, + "result.users.0.alias": "admin", + "result.users.0.user_id": test.ConstAdminID, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: search users without project for User UUID + Name: "test1_09", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "search") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Users without project", + "result.total": float64(10), + "result.users.0.email": test.ConstUserEmail, + "result.users.0.alias": "user", + "result.users.0.user_id": test.ConstUserID, + }, + RequestHeaders: adminHeader, + }, + + { // USER: fake project UUID + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(11), + //---------------------------------------- + "result.members.0.owner_id": nil, + "result.members.0.project_id": nil, + "result.members.0.active": true, + "result.members.0.member_id": "4fc69519-b683-46f0-860c-3e7f12a17563", + "result.members.0.online": nil, + "result.members.0.project_name": "project3", + "result.members.0.role": float64(1), + "result.members.0.schemes_count": float64(16), + "result.members.0.user_name": "Penny", + "result.members.0.locked_at": nil, + "result.members.0.archived_at": nil, + "result.members.0.updated_at": nil, + "result.members.0.created_at": "*", + //---------------------------------------- + "result.members.1.owner_id": nil, + "result.members.1.project_id": nil, + "result.members.1.active": true, + "result.members.1.member_id": "49a10a09-0bb3-48af-99cb-181533692585", + "result.members.1.online": true, + "result.members.1.project_name": "project3", + "result.members.1.role": float64(1), + "result.members.1.schemes_count": float64(1), + "result.members.1.user_name": "Harrison", + "result.members.1.locked_at": nil, + "result.members.1.archived_at": nil, + "result.members.1.updated_at": nil, + "result.members.1.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: ignored user_id + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(11), + "result.members.0.member_id": "*", + "result.members.1.member_id": "*", + "result.members.11.member_id": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: search users without project + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "search"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + { // USER: search users without project for User UUID + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, "search") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, } - New(webHandler).Routes() // add test module handler - testHandler.FinishHandler() + test.RunCaseAPITests(t, app, testTable) +} - adminInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-admin@werbot.net", - Password: "test-admin@werbot.net", - }) +func TestHandler_projectMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) - userInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-user@werbot.net", - Password: "test-user@werbot.net", - }) + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathMembersProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member", + "result.member_id": test.ConstUserProjectMemberID, + "result.owner_id": test.ConstAdminID, + "result.owner_name": "Penny", + "result.project_id": test.ConstAdminProject1ID, + "result.project_name": "project1", + "result.role": float64(1), + "result.user_id": test.ConstUserID, + "result.user_name": "Carly", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID, test.ConstUserProjectMemberID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID, test.ConstFakeID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member", + "result.active": true, + "result.owner_id": "c180ad5c-0c65-4cee-8725-12931cb5abb3", + "result.project_id": "d958ee44-a960-420e-9bbf-c7a35084c4aa", + "result.member_id": "4fc69519-b683-46f0-860c-3e7f12a17563", + "result.user_id": "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + "result.owner_name": "Carly", + "result.project_name": "project3", + "result.role": float64(1), + "result.user_name": "Penny", + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member", + "result.member_id": "4fc69519-b683-46f0-860c-3e7f12a17563", + "result.project_name": "project3", + "result.role": float64(1), + "result.user_name": "Penny", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID, test.ConstUserProjectMemberID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID, test.ConstFakeID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) } -func apiTest() *apitest.APITest { - return apitest.New(). - Debug(). - HandlerFunc(testHandler.Handler) +func TestHandler_addProjectMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: pathMembersProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.user_id": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "user_id": "test", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.user_id": "value must be a valid UUID", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member added", + "result.member_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": test.ConstFakeID, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID) + "?owner_id=c180ad5c-0c65-4cee-8725-12931cb5abb3", + StatusCode: 200, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member added", + "result.member_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.user_id": "value is required", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "user_id": "test", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.user_id": "value must be a valid UUID", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "tes2_03", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member added", + "result.member_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": test.ConstFakeID, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID) + "?owner_id=c180ad5c-0c65-4cee-8725-12931cb5abb3", + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_07", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "user_id": "51c12bb6-2da6-491d-8003-b024f54a1491", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) } -func TestHandler_getMembers(t *testing.T) { - t.Parallel() - - testCases := []tests.TestCase{ - // Unauthorized user error - { - Name: "getMembers_01", - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - - // ROLE_ADMIN - Error validating body params - { - Name: "ROLE_ADMIN_getMembers_01", - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - End(), - RespondStatus: http.StatusBadRequest, - }, - - // ROLE_ADMIN - Submitted in wrong format - { - Name: "ROLE_ADMIN_getMembers_02", - RequestBody: map[string]string{"project_id": "5d013c61-83d1-4b59-b430-1edfd5f2b8d9"}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.projectid`, "projectId is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - - // ROLE_ADMIN - List of servers available in this project - // Project owner, administrator - { - Name: "ROLE_ADMIN_getMembers_03", - RequestBody: map[string]string{"project_id": "ROLE_ADMIN_getMembers_03"}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, "servers available in this project"). - End(), - RespondStatus: http.StatusOK, - }, - - // ROLE_ADMIN - NotFound - List of servers available in this project - // Project owner, user - { - Name: "ROLE_ADMIN_getMembers_04", - RequestBody: map[string]int{"project_id": 3, "owner_id": 2}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, +func TestHandler_updateProjectMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: pathMembersProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: broken member UUID + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: broken member UUID + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: update a member active + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: update a member active + Name: "test1_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "role": 1, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "role": 1, + }, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "role": 2, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563") + "?owner_id=" + test.ConstUserID, + StatusCode: 400, + RequestBody: test.BodyTable{ + "role": 3, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + }, + RequestHeaders: adminHeader, + }, + + { // USER: broken member UUID + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: broken member UUID + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: update a member active + Name: "test2_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: userHeader, + }, + { // USER: update a member active + Name: "test2_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "role": 1, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 400, + RequestBody: test.BodyTable{ + "role": 1, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 400, + RequestBody: test.BodyTable{ + "role": 1, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_removeProjectMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: pathMembersProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "4fc69519-b683-46f0-860c-3e7f12a17563") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member deleted", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, "49a10a09-0bb3-48af-99cb-181533692585"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstUserProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersProject, test.ConstAdminProject1ID, test.ConstUserProjectMemberID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_projectMembersInvite(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathMembersInviteProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgInviteNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invites", + "result.total": float64(13), + "result.invites.0.status": float64(2), + "result.invites.0.email": test.ConstUserEmail, + "result.invites.0.name": "user", + "result.invites.0.surname": "test1", + "result.invites.0.updated_at": nil, + "result.invites.0.created_at": "*", + // -- + "result.invites.13.id": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgInviteNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invites", + "result.total": float64(3), + // -- + "result.invites.0.status": float64(2), + "result.invites.0.email": "admin@werbot.net", + "result.invites.0.name": "admin", + "result.invites.0.surname": "admin1", + "result.invites.0.updated_at": nil, + "result.invites.0.created_at": "*", + // -- + "result.invites.1.status": float64(1), + "result.invites.1.email": "user@werbot.net", + "result.invites.1.name": "user", + "result.invites.1.surname": "test1", + "result.invites.1.updated_at": nil, + "result.invites.1.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgInviteNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invites", + "result.total": float64(3), + // -- + "result.invites.0.status": float64(2), + "result.invites.0.email": "admin@werbot.net", + "result.invites.0.name": "admin", + "result.invites.0.surname": "admin1", + "result.invites.0.updated_at": nil, + "result.invites.0.created_at": "*", + // -- + "result.invites.1.status": float64(1), + "result.invites.1.email": "user@werbot.net", + "result.invites.1.name": "user", + "result.invites.1.surname": "test1", + "result.invites.1.updated_at": nil, + "result.invites.1.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: ignored Owner UUID + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invites", + "result.total": float64(3), + // -- + "result.invites.0.status": float64(2), + "result.invites.0.email": "admin@werbot.net", + "result.invites.0.name": "admin", + "result.invites.0.surname": "admin1", + "result.invites.0.updated_at": nil, + "result.invites.0.created_at": "*", + // -- + "result.invites.1.status": float64(1), + "result.invites.1.email": "user@werbot.net", + "result.invites.1.name": "user", + "result.invites.1.surname": "test1", + "result.invites.1.updated_at": nil, + "result.invites.1.created_at": "*", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addProjectMemberInvite(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: pathMembersInviteProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.email": "value is required", + "result.user_name": "value is required", + "result.user_surname": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": "test", + "user_name": "ab", + "user_surname": "ab", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.email": "must be a valid email", + "result.user_name": "required field (3 to 30 characters)", + "result.user_surname": "required field (3 to 30 characters)", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "email": "user90@werbot.net", + "user_name": "User", + "user_surname": "Name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invited", + "result.token": "*", + "result.status": float64(1), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "email": "user99@werbot.net", + "user_name": "User", + "user_surname": "Name", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "email": "user99@werbot.net", + "user_name": "User", + "user_surname": "Name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invited", + "result.token": "*", + "result.status": float64(1), + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.email": "value is required", + "result.user_name": "value is required", + "result.user_surname": "value is required", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": "test", + "user_name": "ab", + "user_surname": "ab", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.email": "must be a valid email", + "result.user_name": "required field (3 to 30 characters)", + "result.user_surname": "required field (3 to 30 characters)", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "email": "user99@werbot.net", + "user_name": "User", + "user_surname": "Name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member invited", + "result.token": "*", + "result.status": float64(1), + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "email": "user99@werbot.net", + "user_name": "User", + "user_surname": "Name", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "email": "user99@werbot.net", + "user_name": "User", + "user_surname": "Name", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, }, } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Get("/v1/members"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_deleteProjectMemberInvite(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: pathMembersInviteProject, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID, test.ConstAdminProject1InviteID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstFakeID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID, test.ConstAdminProject1InviteID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Invite deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID, test.ConstUserProject1InviteID) + "?owner_id" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID, "15348c8a-894e-49e6-88a9-79aa058892f3") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Invite deleted", + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstFakeID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstUserProject1ID, "3ec414fc-0bbe-44b8-b1d2-ff99171b4963"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Invite deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID, test.ConstAdminProject1InviteID) + "?owner_id" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersInviteProject, test.ConstAdminProject1ID, "15348c8a-894e-49e6-88a9-79aa058892f3") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, } + + test.RunCaseAPITests(t, app, testTable) +} + +// TODO 1. registration if there is no user, 2. authorization if the user is not authorized, +func TestHandler_membersInviteActivate(t *testing.T) { + app, teardownTestCase, _, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // fake invite + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInvite, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // USER: request + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersInvite, test.ConstUserMemberInviteID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Invite confirmed", + }, + RequestHeaders: userHeader, + }, + // TODO add other test cases to activate member invite + } + + test.RunCaseAPITests(t, app, testTable) } -*/ diff --git a/api/member/routes_test.go b/api/member/routes_test.go new file mode 100644 index 00000000..368e83a2 --- /dev/null +++ b/api/member/routes_test.go @@ -0,0 +1,27 @@ +package member + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathMembers = "/v1/members" + pathMembersProject = pathMembers + "/project" + pathMembersScheme = pathMembers + "/scheme" + pathMembersInvite = pathMembers + "/invite" + pathMembersInviteProject = pathMembersInvite + "/project" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/member/scheme_test.go b/api/member/scheme_test.go new file mode 100644 index 00000000..bd39c783 --- /dev/null +++ b/api/member/scheme_test.go @@ -0,0 +1,1031 @@ +package member + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/utils/test" +) + +func TestHandler_schemeMembers(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathMembersScheme, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(1), + "result.members.0.scheme_member_id": "8ca0ad93-4338-44cb-93dd-3f57272d0ffa", + "result.members.0.user_id": "c180ad5c-0c65-4cee-8725-12931cb5abb3", + "result.members.0.user_name": "Carly", + "result.members.0.user_surname": "Bender", + "result.members.0.user_alias": "user", + "result.members.0.active": true, + "result.members.0.online": nil, + "result.members.0.email": "user@werbot.net", + "result.members.0.locked_at": nil, + "result.members.0.archived_at": nil, + "result.members.0.updated_at": nil, + "result.members.0.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: search users without scheme + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, "search"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members without scheme", + "result.total": float64(6), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: search users without scheme + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, "search") + "?alias=user1", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members without scheme", + "result.total": float64(1), + "result.members.0.member_id": "92de7a44-08fc-4d42-aab5-37f86fd598a2", + "result.members.0.email": "user1@werbot.net", + "result.members.0.online": true, + "result.members.0.active": true, + "result.members.0.role": float64(1), + "result.members.0.user_alias": "user1", + "result.members.0.user_name": "Harrison", + "result.members.0.user_surname": "Bowling", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(1), + "result.members.0.email": "admin@werbot.net", + "result.members.0.scheme_member_id": "57ea9d56-5382-4749-99bb-b71a38d448b0", + "result.members.0.user_id": "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + "result.members.0.user_name": "Penny", + "result.members.0.user_surname": "Hoyle", + "result.members.0.user_alias": "admin", + "result.members.0.active": true, + "result.members.0.online": true, + "result.members.0.locked_at": nil, + "result.members.0.archived_at": nil, + "result.members.0.updated_at": "*", + "result.members.0.created_at": "*", + // -- + "result.members.1.scheme_member_id": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_08", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "search") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members without scheme", + "result.total": float64(11), + "result.members.0.member_id": "7f717b66-34b5-4707-b9b8-0f63e8e034de", + "result.members.0.email": "user9@werbot.net", + "result.members.0.online": true, + "result.members.0.active": true, + "result.members.0.role": float64(1), + "result.members.0.user_alias": "user9", + "result.members.0.user_name": "Brock", + "result.members.0.user_surname": "Solomon", + // -- + "result.members.11.scheme_member_id": nil, + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members", + "result.total": float64(1), + "result.members.0.scheme_member_id": "57ea9d56-5382-4749-99bb-b71a38d448b0", + "result.members.0.user_id": nil, + "result.members.0.user_name": "Penny", + "result.members.0.user_surname": "Hoyle", + "result.members.0.user_alias": "admin", + "result.members.0.active": true, + "result.members.0.online": true, + "result.members.0.email": nil, + "result.members.0.locked_at": nil, + "result.members.0.archived_at": nil, + "result.members.0.updated_at": nil, + "result.members.0.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: search users without scheme + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "search"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members without scheme", + "result.total": float64(11), + }, + RequestHeaders: userHeader, + }, + { // USER: search users without scheme + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "search") + "?alias=user1", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Members without scheme", + "result.total": float64(3), + "result.members.0.member_id": "de040931-6977-4629-aab0-6d621ff368a3", + "result.members.0.email": "user10@werbot.net", + "result.members.0.online": true, + "result.members.0.active": true, + "result.members.0.role": float64(1), + "result.members.0.user_alias": "user10", + "result.members.0.user_name": "Clinton", + "result.members.0.user_surname": "Proctor", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_08", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, "search") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_schemeMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathMembersScheme, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstUserScheme1MemberID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstFakeID, test.ConstUserScheme1MemberID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstUserScheme1MemberID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member", + "result.scheme_member_id": "8ca0ad93-4338-44cb-93dd-3f57272d0ffa", + "result.user_id": "c180ad5c-0c65-4cee-8725-12931cb5abb3", + "result.user_name": "Carly", + "result.user_surname": "Bender", + "result.user_alias": "user", + "result.active": true, + "result.online": nil, + "result.email": "user@werbot.net", + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, test.ConstUserScheme1MemberID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "57ea9d56-5382-4749-99bb-b71a38d448b0") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member", + "result.scheme_member_id": "57ea9d56-5382-4749-99bb-b71a38d448b0", + "result.user_id": "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + "result.user_name": "Penny", + "result.user_surname": "Hoyle", + "result.user_alias": "admin", + "result.active": true, + "result.online": true, + "result.email": "admin@werbot.net", + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": "*", + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstFakeID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member", + "result.scheme_member_id": "57ea9d56-5382-4749-99bb-b71a38d448b0", + "result.user_id": nil, + "result.user_name": "Penny", + "result.user_surname": "Hoyle", + "result.user_alias": "admin", + "result.active": true, + "result.online": true, + "result.email": nil, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, "de040931-6977-4629-aab0-6d621ff368a3") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "de040931-6977-4629-aab0-6d621ff368a3") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addSchemeMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: pathMembersScheme, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.member_id": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "member_id": "test", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.member_id": "value must be a valid UUID", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": test.ConstFakeID, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "member_id": "92de7a44-08fc-4d42-aab5-37f86fd598a2", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member added", + "result.scheme_member_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: member from other team + Name: "test1_05", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": "43ab80dd-ffe6-4881-aa8d-52b56ea715d2", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": "43ab80dd-ffe6-4881-aa8d-52b56ea715d2", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "member_id": "e7492145-3b8e-4d06-a3a7-81fb6deb3571", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member added", + "result.scheme_member_id": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.member_id": "value is required", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "member_id": "test", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.member_id": "value must be a valid UUID", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_03", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": test.ConstFakeID, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "member_id": "de040931-6977-4629-aab0-6d621ff368a3", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member added", + "result.scheme_member_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: member from other team + Name: "test2_05", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": "bac61932-ac1d-4f3a-b842-17b136bd1346", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": "bac61932-ac1d-4f3a-b842-17b136bd1346", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_07", + Method: http.MethodPost, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "member_id": "bac61932-ac1d-4f3a-b842-17b136bd1346", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_updateSchemeMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: pathMembersScheme, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstUserScheme1MemberID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstUserScheme1MemberID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: turn active member + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstUserScheme1MemberID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: broken scheme UUID + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstFakeID, test.ConstUserScheme1MemberID), + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: active a member from someone else's project + Name: "test1_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH2ID, test.ConstUserScheme2MemberID), + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, test.ConstUserScheme2MemberID) + "?owner_id=" + test.ConstFakeID, + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, RequestHeaders: adminHeader, + }, + { // ADMIN: active a member from someone else's project with user UUID + Name: "test1_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, test.ConstUserScheme2MemberID) + "?owner_id=" + test.ConstUserID, + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: turn active member + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member updated", + }, + RequestHeaders: userHeader, + }, + { // USER: broken scheme UUID + Name: "test2_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstFakeID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: active a member from someone else's project + Name: "test2_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, "57ea9d56-5382-4749-99bb-b71a38d448b0") + "?owner_id=" + test.ConstFakeID, + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: active a member from someone else's project with user UUID + Name: "test2_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, "57ea9d56-5382-4749-99bb-b71a38d448b0") + "?owner_id=" + test.ConstUserID, + RequestBody: test.BodyTable{ + "active": true, + }, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_deleteSchemeMember(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: pathMembersScheme, + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request + Name: "test0_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstFakeID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: fake member UUID + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: is not the owner of the scheme + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, test.ConstUserScheme2MemberID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH1ID, "8ca0ad93-4338-44cb-93dd-3f57272d0ffa"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, test.ConstUserScheme2MemberID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: is not the owner of the scheme but can pass the user_id + Name: "test1_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH2ID, test.ConstUserScheme2MemberID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member deleted", + }, + RequestHeaders: adminHeader, + }, + + { // USER: fake member UUID + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: is not the owner of the scheme + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "8ca0ad93-4338-44cb-93dd-3f57272d0ffa"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstUserSchemeSSH1ID, "57ea9d56-5382-4749-99bb-b71a38d448b0"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Member deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH2ID, "8ca0ad93-4338-44cb-93dd-3f57272d0ffa") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: is not the owner of the scheme but can pass the user_id + Name: "test2_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathMembersScheme, test.ConstAdminSchemeSSH2ID, "8ca0ad93-4338-44cb-93dd-3f57272d0ffa") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/ping/ping_test.go b/api/ping/ping_test.go index 20fa0654..7ab30854 100644 --- a/api/ping/ping_test.go +++ b/api/ping/ping_test.go @@ -1,82 +1,31 @@ package ping import ( - "bytes" - "encoding/json" - "io" "net/http" - "net/http/httptest" "testing" "github.com/werbot/werbot/internal/utils/test" ) -func TestHandler_getPing(t *testing.T) { - app, teardownTestCase := test.API(t) - New(app.Handler).Routes() +func TestHandler_ping(t *testing.T) { + app, teardownTestCase := setupTest(t) defer teardownTestCase(t) - testTable := []struct { - name string // The name of the test - method string // The HTTP method to use in our call - path string // The URL path that is being requested - statusCode int // The expected response status code - body string // The expected response body, as string - requestBody map[string]interface{} // The request body to sent with the request - requestHeaders map[string]string // The headers that are being set for the request - headers map[string]string // The response headers we want to test on - }{ - { - name: "GET ping to get a answer", - method: http.MethodGet, - path: "/ping", - statusCode: 200, - body: "pong", + testTable := []test.APITable{ + { // GET ping to get a answer + Name: "test0_01", + Method: http.MethodGet, + Path: "/ping", + StatusCode: 200, }, - { - name: "POST ping method not allowed", - method: http.MethodPost, - path: "/ping", - statusCode: 405, - body: `Method Not Allowed`, + { // POST ping method not allowed + Name: "test0_02", + Method: http.MethodPost, + Path: "/ping", + StatusCode: 404, + Body: test.BodyNotFound, }, } - for _, tc := range testTable { - t.Run(tc.name, func(t *testing.T) { - // Create and send request - rbody, _ := json.Marshal(tc.requestBody) - request := httptest.NewRequest(tc.method, tc.path, bytes.NewReader(rbody)) - request.Header.Add(`Content-Type`, `application/json`) - - // Request Headers - for k, v := range tc.requestHeaders { - request.Header.Add(k, v) - } - - response, _ := app.App.Test(request) - - // Status Code - statusCode := response.StatusCode - if statusCode != tc.statusCode { - t.Errorf("StatusCode was incorrect, got: %d, want: %d.", statusCode, tc.statusCode) - } - - // Headers - for k, want := range tc.headers { - headerValue := response.Header.Get(k) - if headerValue != want { - t.Errorf("Response header '%s' was incorrect, got: '%s', want: '%s'", k, headerValue, want) - } - } - - // Response Body - body, _ := io.ReadAll(response.Body) - actual := string(body) - if actual != tc.body { - t.Errorf("Body was incorrect, got: %v, want: %v", actual, tc.body) - } - }) - } - + test.RunCaseAPITests(t, app, testTable) } diff --git a/api/ping/routes_test.go b/api/ping/routes_test.go new file mode 100644 index 00000000..a6938182 --- /dev/null +++ b/api/ping/routes_test.go @@ -0,0 +1,15 @@ +package ping + +import ( + "testing" + + "github.com/werbot/werbot/internal/utils/test" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T)) { + app, teardownTestCase := test.API(t) + New(app.Handler).Routes() + app.AddRoute404() + + return app, teardownTestCase +} diff --git a/api/project/key_test.go b/api/project/key_test.go new file mode 100644 index 00000000..4f9d93a6 --- /dev/null +++ b/api/project/key_test.go @@ -0,0 +1,646 @@ +package project + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/crypto" +) + +func TestHandler_projectKeys(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project keys", + "result.total": float64(1), + "result.keys.0.key_id": "a1059d92-d032-427c-9444-571967d1f9a5", + "result.keys.0.online": true, + "result.keys.0.key": "3GZBSPqDi7r1FDzYMUNV41l9HOJlb9y8b3ZI9", + "result.keys.0.secret": "AweHj3rtANGfy0gG021ptsDzYMwYmgwnY11CC", + "result.keys.0.locked_at": nil, + "result.keys.0.archived_at": nil, + "result.keys.0.updated_at": nil, + "result.keys.0.created_at": "*", + // -- + "result.keys.1.key_id": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project keys", + "result.total": float64(1), + "result.keys.0.key_id": "268def26-4efb-47c4-b699-f34903cf05f5", + "result.keys.0.key": "5tYJOkr3oLCOEvhw3nB83AmDzYM7yJsJ0Sonl", + "result.keys.0.secret": "aDzYMy9g3mmsq3XazPLvvCbj4kJAsgatxBDVW", + "result.keys.0.online": true, + "result.keys.0.locked_at": nil, + "result.keys.0.archived_at": nil, + "result.keys.0.updated_at": nil, + "result.keys.0.created_at": "*", + // -- + "result.keys.1.key_id": nil, + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project keys", + "result.total": float64(1), + "result.keys.0.key_id": "268def26-4efb-47c4-b699-f34903cf05f5", + "result.keys.0.key": "5tYJOkr3oLCOEvhw3nB83AmDzYM7yJsJ0Sonl", + "result.keys.0.secret": "aDzYMy9g3mmsq3XazPLvvCbj4kJAsgatxBDVW", + "result.keys.0.online": true, + "result.keys.0.locked_at": nil, + "result.keys.0.archived_at": nil, + "result.keys.0.updated_at": nil, + "result.keys.0.created_at": "*", + // -- + "result.keys.1.key_id": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_projectKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + // public section + { // unauthorized request with fake api key + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, "key", crypto.NewPassword(37, false)), + StatusCode: 404, + Body: test.BodyNotFound, + }, + { // unauthorized request with valid api key + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, "key", "3GZBSPqDi7r1FDzYMUNV41l9HOJlb9y8b3ZI9"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key", + "result.project_id": "2bef1080-cd6e-49e5-8042-1224cf6a3da9", + }, + }, + + // private section + { // unauthorized request + Name: "test0_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "test", test.ConstAdminProject1ApiID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key", + "result.key": "3GZBSPqDi7r1FDzYMUNV41l9HOJlb9y8b3ZI9", + "result.secret": "AweHj3rtANGfy0gG021ptsDzYMwYmgwnY11CC", + "result.online": true, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key", + "result.key": "5tYJOkr3oLCOEvhw3nB83AmDzYM7yJsJ0Sonl", + "result.secret": "aDzYMy9g3mmsq3XazPLvvCbj4kJAsgatxBDVW", + "result.online": true, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "test", "268def26-4efb-47c4-b699-f34903cf05f5"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key", + "result.key": "5tYJOkr3oLCOEvhw3nB83AmDzYM7yJsJ0Sonl", + "result.secret": "aDzYMy9g3mmsq3XazPLvvCbj4kJAsgatxBDVW", + "result.online": true, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addProjectKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.key_id": "*", + "result.key": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.key_id": "*", + "result.key": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.key_id": "*", + "result.key": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodPost, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_deleteProjectKey(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", "268def26-4efb-47c4-b699-f34903cf05f5") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key deleted", + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstFakeID, "keys", test.ConstAdminProject1ApiID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID, "keys", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, "f85c4597-005d-48a6-b643-a21adf19a4aa", "keys", "81ae0bbe-b746-44a6-a1f4-8467ff17bf5e"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project key deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, "e29568e6-c8f8-4555-a531-58a44554046f", "keys", "974c8001-4f8a-4ccc-b9db-9cf29e1405b2") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, "e29568e6-c8f8-4555-a531-58a44554046f", "keys", "974c8001-4f8a-4ccc-b9db-9cf29e1405b2") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "result": "Member not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/project/project_test.go b/api/project/project_test.go index 8d364fff..2c786e28 100644 --- a/api/project/project_test.go +++ b/api/project/project_test.go @@ -1,434 +1,855 @@ package project -/* import ( - "context" - "encoding/json" "net/http" "testing" - "time" - "github.com/google/uuid" - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - accountpb "github.com/werbot/werbot/api/proto/account" - projectpb "github.com/werbot/werbot/api/proto/project" - "github.com/werbot/werbot/api" - "github.com/werbot/werbot/api/auth" - "github.com/werbot/werbot/internal" - "github.com/werbot/werbot/internal/tests" - "github.com/werbot/werbot/internal/web/middleware" -) - -var ( - testHandler *tests.TestHandler - adminInfo *tests.UserInfo - userInfo *tests.UserInfo + "github.com/werbot/werbot/internal/utils/test" ) -func init() { - testHandler = tests.InitTestServer("../../../.env") - auth.New(&web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Cache: testHandler.Cache, - Auth: *testHandler.Auth, - }).Routes() - authMiddleware := middleware.Auth(testHandler.Cache).Execute() - webHandler := &web.Handler{ - App: testHandler.App, - Grpc: testHandler.GRPC, - Auth: authMiddleware, - } - - New(webHandler).Routes() // add test module handler - testHandler.FinishHandler() // init finale handler for apitest +func TestHandler_projects(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) - adminInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-admin@werbot.net", - Password: "test-admin@werbot.net", - }) + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathProjects, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with user UUID + Name: "test1_01", + Method: http.MethodGet, + Path: pathProjects + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Projects", + "result.total": float64(3), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with fake user UUID + Name: "test1_02", + Method: http.MethodGet, + Path: pathProjects + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_03", + Method: http.MethodGet, + Path: pathProjects, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Projects", + "result.total": float64(11), + "result.projects.0.alias": "68rwRW", + "result.projects.0.owner_id": "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + "result.projects.0.project_id": "26060c68-5a06-4a57-b87a-be0f1e787157", + "result.projects.0.title": "project7", + "result.projects.0.servers_count": nil, + "result.projects.0.databases_count": nil, + "result.projects.0.applications_count": nil, + "result.projects.0.desktops_count": nil, + "result.projects.0.containers_count": nil, + "result.projects.0.clouds_count": nil, + "result.projects.0.locked_at": nil, + "result.projects.0.archived_at": nil, + "result.projects.0.updated_at": nil, + "result.projects.0.created_at": "*", + // -- + "result.projects.11.alias": nil, + }, + RequestHeaders: adminHeader, + }, - userInfo = testHandler.GetUserInfo(&accountpb.SignIn_Request{ - Email: "test-user@werbot.net", - Password: "test-user@werbot.net", - }) + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: pathProjects, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Projects", + "result.total": float64(3), + }, + RequestHeaders: userHeader, + }, + { // USER: request with user UUID + Name: "test2_02", + Method: http.MethodGet, + Path: pathProjects + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Projects", + "result.total": float64(3), + "result.projects.0.alias": "9Yyz9Z", + "result.projects.0.owner_id": nil, + "result.projects.0.project_id": "83d401e4-fda4-404e-8c2a-da58b03919c1", + "result.projects.0.title": "project13", + "result.projects.0.servers_count": nil, + "result.projects.0.databases_count": nil, + "result.projects.0.applications_count": nil, + "result.projects.0.desktops_count": nil, + "result.projects.0.containers_count": nil, + "result.projects.0.clouds_count": nil, + "result.projects.0.locked_at": nil, + "result.projects.0.archived_at": nil, + "result.projects.0.updated_at": nil, + "result.projects.0.created_at": "*", + // -- + "result.projects.3.alias": nil, + }, + RequestHeaders: userHeader, + }, + } + test.RunCaseAPITests(t, app, testTable) } -func apiTest() *apitest.APITest { - return apitest.New(). - Debug(). - HandlerFunc(testHandler.Handler) -} +func TestHandler_project(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) -func TestHandler_getProject(t *testing.T) { - t.Parallel() + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathProjects, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project", + "result.alias": "Y93iyI", + "result.title": "project1", + "result.servers_count": nil, + "result.databases_count": nil, + "result.applications_count": nil, + "result.desktops_count": nil, + "result.containers_count": nil, + "result.clouds_count": nil, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project", + "result.alias": "C8cXx0", + "result.title": "project3", + "result.servers_count": nil, + "result.databases_count": nil, + "result.applications_count": nil, + "result.desktops_count": nil, + "result.containers_count": nil, + "result.clouds_count": nil, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: adminHeader, + }, - testCases := []tests.TestCase{ - // Cases with an anonymous user - { - Name: "ANONYMOUS_USER_getProject_01", // User not authorized - RequestParam: map[string]string{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - // Cases with an authorized user - { - Name: "ROLE_USER_getProject_01", // List of all projects of user - RequestParam: map[string]string{}, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjects). - Equal(`$.result.total`, float64(1)). - Equal(`$.result.projects[0].owner_id`, userInfo.UserID). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "ROLE_USER_getProject_02", // Error 404 on invalid input - RequestParam: map[string]string{ - "owner_id": uuid.New().String(), - "project_id": uuid.New().String(), - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "ROLE_USER_getProject_03", // Owner_id parameters are not checked - RequestParam: map[string]string{ - "owner_id": uuid.New().String(), - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjects). - Equal(`$.result.total`, float64(1)). - Equal(`$.result.projects[0].owner_id`, userInfo.UserID). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "ROLE_USER_getProject_04", // Error 404 when trying to display a non-existent project - RequestParam: map[string]string{ - "project_id": uuid.New().String(), - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "ROLE_USER_getProject_05", // Error 400 when trying to pass invalid parameters - RequestParam: map[string]string{ - "project_id": "123", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.projectid`, "projectId must be a valid UUID"). - End(), - RespondStatus: http.StatusBadRequest, - }, - // Cases with a user with ADMIN rights - { - Name: "ROLE_ADMIN_getProject_01", // List of all projects of user - RequestParam: map[string]string{}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjects). - Equal(`$.result.total`, float64(2)). - Equal(`$.result.projects[0].owner_id`, adminInfo.UserID). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "ROLE_ADMIN_getProject_02", // Error 404 on invalid input - RequestParam: map[string]string{ - "owner_id": uuid.New().String(), - "project_id": uuid.New().String(), - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "ROLE_ADMIN_getProject_03", // Error 404 when invalid owner ID - RequestParam: map[string]string{ - "owner_id": uuid.New().String(), - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "ROLE_ADMIN_getProject_04", // Error 404 when project of test-user@werbot.net, but not use owner_id - RequestParam: map[string]string{ - "project_id": "69fbe29e-c955-41ad-b0c4-3a474cf01ea9", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgNotFound). - End(), - RespondStatus: http.StatusNotFound, - }, - { - Name: "ROLE_ADMIN_getProject_05", // Shows all projects of another user (test-user@werbot.net) - RequestParam: map[string]string{ - "owner_id": userInfo.UserID, - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjects). - Equal(`$.result.total`, float64(1)). - Equal(`$.result.projects[0].owner_id`, userInfo.UserID). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "ROLE_ADMIN_getProject_06", // Information about another user's project (test-user@werbot.net) - RequestParam: map[string]string{ - "owner_id": userInfo.UserID, - "project_id": "69fbe29e-c955-41ad-b0c4-3a474cf01ea9", - }, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjectInfo). - Equal(`$.result.title`, "test_project3"). - Equal(`$.result.login`, "testproject3"). - End(), - RespondStatus: http.StatusOK, + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project", + "result.alias": "C8cXx0", + "result.title": "project3", + "result.servers_count": nil, + "result.databases_count": nil, + "result.applications_count": nil, + "result.desktops_count": nil, + "result.containers_count": nil, + "result.clouds_count": nil, + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test3_03", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, }, } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Get("/v1/projects"). - QueryParams(tc.RequestParam.(map[string]string)). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) - } + test.RunCaseAPITests(t, app, testTable) } func TestHandler_addProject(t *testing.T) { - t.Parallel() + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) - testCases := []tests.TestCase{ - // Cases with an anonymous user - { - Name: "ANONYMOUS_USER_addProject_01", // User not authorized - RequestBody: projectpb.AddProject_Request{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - // Cases with an authorized user - { - Name: "ROLE_USER_addProject_01", // Error 400 when trying to pass invalid parameters - RequestBody: projectpb.AddProject_Request{ - Title: "", - Login: "", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.login`, "login is a required field"). - Equal(`$.result.title`, "title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "ROLE_USER_addProject_02", // Error 400 when trying to pass invalid parameters - RequestBody: projectpb.AddProject_Request{ - Title: "user", - Login: "user999", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.title`, "title must be at least 5 characters in length"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "ROLE_USER_addProject_03", // Error 400 when trying to pass invalid parameters - RequestBody: projectpb.AddProject_Request{ - Login: "user999", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.title`, "title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "ROLE_USER_addProject_04", - RequestBody: projectpb.AddProject_Request{ - Title: "user999", - Login: "user999", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjectAdded). - End(), - RespondStatus: http.StatusOK, + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value is required", + "result.title": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "ABC", + "title": "12", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value does not match regex pattern `^[a-z0-9]+$`", + "result.title": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "a1b2c3", + "title": "Title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.project_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: pathProjects + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "alias": "a1b2c3", + "title": "Title", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPost, + Path: pathProjects + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "a1b2c3", + "title": "Title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.project_id": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value is required", + "result.title": "value is required", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "ABC", + "title": "12", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value does not match regex pattern `^[a-z0-9]+$`", + "result.title": "value length must be at least 3 characters", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodPost, + Path: pathProjects, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "a1b2c3", + "title": "Title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.project_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: ignored owner_id + Name: "test2_04", + Method: http.MethodPost, + Path: pathProjects + "?owner_id=" + test.ConstFakeID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "a1b2c3", + "title": "Title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.project_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: ignored owner_id + Name: "test2_05", + Method: http.MethodPost, + Path: pathProjects + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "a1b2c3", + "title": "Title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project added", + "result.project_id": "*", + }, + RequestHeaders: userHeader, }, } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - resp := apiTest(). - Post("/v1/projects"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() + test.RunCaseAPITests(t, app, testTable) +} - // delete added project - data := map[string]projectpb.AddProject_Response{} - json.NewDecoder(resp.Response.Body).Decode(&data) - if data["result"].ProjectId != "" { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() +func TestHandler_updateProject(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) - rClient := projectpb.NewProjectHandlersClient(testHandler.GRPC.Client) - rClient.DeleteProject(ctx, &projectpb.DeleteProject_Request{ - OwnerId: tc.RequestUser.UserID, - ProjectId: data["result"].ProjectId, - }) - } - }) + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: pathProjects, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "ABC", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value does not match regex pattern `^[a-z0-9]+$`", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "12", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "a1s2d3", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project updated", + "result": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project updated", + "result": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project updated", + "result": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "q1w2e3", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project updated", + "result": nil, + }, + RequestHeaders: adminHeader, + }, + + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "ABC", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value does not match regex pattern `^[a-z0-9]+$`", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "12", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value length must be at least 3 characters", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "a1s2d3", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project updated", + "result": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "q1w2e3", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, } + + test.RunCaseAPITests(t, app, testTable) } -func TestHandler_patchProject(t *testing.T) { - t.Parallel() +func TestHandler_deleteProject(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) - testCases := []tests.TestCase{ - // Cases with an anonymous user - { - Name: "ANONYMOUS_USER_patchProject_01", // User not authorized - RequestBody: projectpb.UpdateProject_Request{}, - RequestUser: &tests.UserInfo{}, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgUnauthorized). - End(), - RespondStatus: http.StatusUnauthorized, - }, - // Cases with an authorized user - { - Name: "ROLE_USER_patchProject_01", // Error 400 when trying to pass invalid parameters - RequestBody: projectpb.UpdateProject_Request{}, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.projectid`, "projectId is a required field"). - Equal(`$.result.title`, "title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "ROLE_USER_patchProject_02", // Error 400 when trying to pass invalid parameters - RequestBody: projectpb.UpdateProject_Request{ - ProjectId: "d958ee44-a960-420e-9bbf-c7a35084c4aa", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - Equal(`$.message`, internal.MsgFailedToValidateBody). - Equal(`$.result.title`, "title is a required field"). - End(), - RespondStatus: http.StatusBadRequest, - }, - { - Name: "ROLE_USER_patchProject_03", // Fake status 200 (real 404), non-existent project ip - RequestBody: projectpb.UpdateProject_Request{ - ProjectId: "00000000-0000-0000-0000-000000000000", - Title: "user999", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjectUpdated). - End(), - RespondStatus: http.StatusOK, - }, - { - Name: "ROLE_USER_patchProject_04", // Successful data update - RequestBody: projectpb.UpdateProject_Request{ - ProjectId: "d958ee44-a960-420e-9bbf-c7a35084c4aa", - Title: "user999", - }, - RequestUser: userInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, true). - Equal(`$.message`, msgProjectUpdated). - End(), - RespondStatus: http.StatusOK, - }, - // Cases with a user with ADMIN rights - { - Name: "ROLE_ADMIN_patchProject_01", - RequestBody: projectpb.UpdateProject_Request{}, - RequestUser: adminInfo, - RespondBody: jsonpath.Chain(). - Equal(`$.success`, false). - End(), - RespondStatus: http.StatusBadRequest, + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: pathProjects, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project deleted", + "result": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project deleted", + "result": nil, + }, + RequestHeaders: adminHeader, }, - } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - apiTest(). - Patch("/v1/projects"). - JSON(tc.RequestBody). - Header("Authorization", "Bearer "+tc.RequestUser.Tokens.Access). - Expect(t). - Assert(tc.RespondBody). - Status(tc.RespondStatus). - End() - }) + { // USER: + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstUserProject1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Project deleted", + "result": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathProjects, test.ConstAdminProject1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Project not found", + }, + RequestHeaders: userHeader, + }, } + + test.RunCaseAPITests(t, app, testTable) } -*/ diff --git a/api/project/routes_test.go b/api/project/routes_test.go new file mode 100644 index 00000000..19c6364e --- /dev/null +++ b/api/project/routes_test.go @@ -0,0 +1,21 @@ +package project + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const pathProjects = "/v1/projects" + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/scheme/routes_test.go b/api/scheme/routes_test.go new file mode 100644 index 00000000..be075ada --- /dev/null +++ b/api/scheme/routes_test.go @@ -0,0 +1,50 @@ +package scheme + +import ( + "context" + "fmt" + "testing" + "time" + + "google.golang.org/protobuf/encoding/protojson" + + "github.com/werbot/werbot/api/auth" + keypb "github.com/werbot/werbot/internal/grpc/key/proto/key" + "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/crypto" + "github.com/werbot/werbot/pkg/storage/redis" +) + +const pathSchemes = "/v1/schemes" + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} + +func serverKeygen(rd *redis.Connect, uuid string, empty bool) func() { + return func() { + cacheKeyStr := fmt.Sprintf("tmp_key_ssh:%s", uuid) + expiration := time.Duration(10 * float64(time.Second)) + + if empty { + _ = rd.Client.Set(context.Background(), cacheKeyStr, "{}", expiration) + } else { + newKeySSH, _ := crypto.NewSSHKey(keypb.KeyType_ed25519.String()) + schemeKey := &keypb.SchemeKey{ + Public: string(newKeySSH.PublicKey), + Private: string(newKeySSH.PrivateKey), + Passphrase: newKeySSH.Passphrase, + FingerPrint: newKeySSH.FingerPrint, + } + json, _ := protojson.Marshal(schemeKey) + _ = rd.Client.Set(context.Background(), cacheKeyStr, string(json), expiration) + } + } +} diff --git a/api/scheme/scheme_test.go b/api/scheme/scheme_test.go new file mode 100644 index 00000000..d278bebc --- /dev/null +++ b/api/scheme/scheme_test.go @@ -0,0 +1,3697 @@ +package scheme + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/trace" + "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/crypto" + "github.com/werbot/werbot/pkg/uuid" +) + +func TestHandler_schemes(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: broken request without project UUID + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with fake UUID + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, "server"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with servers + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Servers", + "result.total": float64(20), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with databases + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "database"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Databases", + "result.total": float64(27), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with desktops + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "desktop"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Desktops", + "result.total": float64(6), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with containers + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "container"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Containers", + "result.total": float64(6), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with clouds + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "cloud"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Clouds", + "result.total": float64(15), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with applications + Name: "test1_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "application"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Applications", + "result.total": float64(3), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request + Name: "test1_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "test"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with pagination + Name: "test1_10", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server") + "?limit=2&offset=0", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Servers", + "result.total": float64(20), + "result.servers.2": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with fake user UUID + Name: "test1_11", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does not belong user UUID + Name: "test1_12", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does belong user UUID + Name: "test1_13", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Servers", + "result.total": float64(11), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does belong user UUID with pagination + Name: "test1_14", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server") + "?limit=2&offset=0&owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Servers", + "result.total": float64(11), + }, + RequestHeaders: adminHeader, + }, + + { // USER: broken request without project UUID + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with fake UUID + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, "server"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: default request + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Servers", + "result.total": float64(11), + }, + RequestHeaders: userHeader, + }, + { // USER: default request with fake user UUID + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server") + "?owner_id=" + test.ConstFakeID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Servers", + "result.total": float64(11), + }, + RequestHeaders: userHeader, + }, + { // USER: default request with the team does belong user UUID + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_scheme(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with fake scheme UUID + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with fake project UUID + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme", + "result.address": "secret.net.google.com", + "result.active": nil, + "result.online": true, + "result.audit": nil, + "result.project_id": test.ConstAdminProject1ID, + "result.auth_method": float64(1), + "result.scheme_type": float64(103), + "result.title": "Git server", + "result.alias": "onxzU5", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the server does not belong user UUID + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does not belong user UUID + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does belong user UUID + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme", + "result.active": true, + "result.address": "127.0.0.4", + "result.audit": nil, + "result.online": nil, + "result.project_id": test.ConstUserProject1ID, + "result.auth_method": float64(1), + "result.scheme_type": float64(103), + "result.title": "Storage server backup", + "result.alias": "JiepgT", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with fake scheme UUID + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with fake project UUID + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: base request + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme", + "result.address": "127.0.0.4", + "result.active": true, + "result.audit": nil, + "result.online": nil, + "result.auth_method": float64(1), + "result.scheme_type": float64(103), + "result.title": "Storage server backup", + "result.alias": "JiepgT", + }, + RequestHeaders: userHeader, + }, + { // USER: default request with the scheme does not belong user UUID + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: default request with the project does not belong user UUID + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: default request with the project does belong user UUID + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addScheme(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: base request without access information + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{}, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.access": "exactly one field is required in oneof", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with broken scheme + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "test": test.BodyTable{ + "alias": "alias", + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.access": "exactly one field is required in oneof", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "address": "domain,com", // broken + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.server_ssh.address": "value must be a valid hostname, or ip address", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request + Name: "test1_05", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "address": "127.0.0.300", // broken + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.server_ssh.address": "value must be a valid hostname, or ip address", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request + Name: "test1_06", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "address": "domain,com", // broken + "port": float64(100000), // broken + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.server_ssh.address": "value must be a valid hostname, or ip address", + "scheme.server_ssh.port": "value must be greater than or equal to 1 and less than 65536", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request + Name: "test1_07", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": uuid.New(), + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Key not found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with autogenerate (use key UUID - 00000000-0000-0000-0000-000000000000) + Name: "test1_08", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with generated key UUID + Name: "test1_09", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": "aac78aae-2036-468a-a12f-beadf7bd07ec", + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: adminHeader, + PreWorkHook: serverKeygen(app.Redis, "aac78aae-2036-468a-a12f-beadf7bd07ec", true), + }, + { // ADMIN: base request with password + Name: "test1_10", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "password": test.BodyTable{ + "login": "login", + "password": crypto.NewPassword(8, false), + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with small password + Name: "test1_11", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "password": test.BodyTable{ + "login": "login", + "password": crypto.NewPassword(7, false), // broken + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.server_ssh.password.password": "value length must be at least 8 characters", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with big password + Name: "test1_12", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "password": test.BodyTable{ + "login": "login", + "password": crypto.NewPassword(33, false), // broken + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "scheme.server_ssh.password.password": "value length must be at most 32 characters", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with fake project UUID + Name: "test1_13", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, "server"), + StatusCode: 404, + RequestBody: test.BodyTable{}, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does not belong user UUID + Name: "test1_14", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server"), + StatusCode: 404, + RequestBody: test.BodyTable{}, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with the project does belong user UUID + Name: "test1_15", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: base request + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server"), + StatusCode: 404, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": uuid.New(), + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Key not found", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with autogenerate (use key UUID - 00000000-0000-0000-0000-000000000000) + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with generated key UUID + Name: "test2_03", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": "aac78aae-2036-468a-a12f-beadf7bd07ec", + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: userHeader, + PreWorkHook: serverKeygen(app.Redis, "aac78aae-2036-468a-a12f-beadf7bd07ec", true), + }, + { // USER: base request with password + Name: "test2_04", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, "server"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "password": test.BodyTable{ + "login": "login", + "password": crypto.NewPassword(8, false), + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme added", + "result.scheme_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: request with fake project UUID + Name: "test2_05", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, "server"), + StatusCode: 404, + RequestBody: test.BodyTable{}, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: default request with the project does not belong user UUID + Name: "test2_06", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server"), + StatusCode: 404, + RequestBody: test.BodyTable{}, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: default request with the project does belong user UUID + Name: "test2_07", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, "server") + "?owner_id=" + test.ConstAdminID, + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "title", + "audit": true, + "active": true, + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias", + "address": "127.0.0.1", + "port": float64(10000), + "key": test.BodyTable{ + "login": "login", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_updateScheme(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with the user does not have access to the project UUID and scheme UUID + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with the user does not have access to the scheme UUID + Name: "test1_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with the user has access to the project UUID and the scheme UUID + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with active parameter + Name: "test1_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": false, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with online parameter + Name: "test1_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "online": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with online parameter + Name: "test1_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value length must be at least 5 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with online parameter + Name: "test1_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "new title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request without parameters + Name: "test1_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with fake setting + Name: "test1_11", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "test": test.BodyTable{}, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with info parameters + Name: "test1_12", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias2", + "address": "127.0.0.255", + "port": float64(23456), + "password": test.BodyTable{ + "login": "newLogin", + "password": "newPassword", + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with info parameters + Name: "test1_13", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH2ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias2", + "address": "127.0.0.255", + "port": float64(23456), + "key": test.BodyTable{ + "login": "newLogin", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with info parameters + Name: "test1_14", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH2ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "key": test.BodyTable{ + "login": "newLogin", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with broken scheme UUID + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with the user UUID (ignored) does not have access to the project UUID and scheme UUID + Name: "test2_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + { // USER: request with the user UUID does not have access UUID to the stranger scheme UUID + Name: "test2_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with the user UUID (ignored) has access to the strangers project UUID and the scheme UUID + Name: "test2_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "audit": true, + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: base request with active parameter + Name: "test2_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with online parameter + Name: "test2_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "online": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with online parameter + Name: "test2_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "title": "", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.title": "value length must be at least 5 characters", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with online parameter + Name: "test2_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "title": "new title", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with fake setting + Name: "test2_11", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 400, + RequestBody: test.BodyTable{ + "test": test.BodyTable{}, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with info parameters + Name: "test2_12", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias2", + "address": "127.0.0.255", + "port": float64(23456), + "password": test.BodyTable{ + "login": "newLogin", + "password": "newPassword", + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with info parameters + Name: "test2_13", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH2ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "alias": "alias2", + "address": "127.0.0.255", + "port": float64(23456), + "key": test.BodyTable{ + "login": "newLogin", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + { // USER: base request with info parameters + Name: "test2_14", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH2ID), + StatusCode: 200, + RequestBody: test.BodyTable{ + "scheme": test.BodyTable{ + "server_ssh": test.BodyTable{ + "key": test.BodyTable{ + "login": "newLogin", + "key_id": test.ConstFakeID, + }, + }, + }, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme updated", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_deleteScheme(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + + { // ADMIN: request with broken scheme UUID + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with the user does not have access to the project UUID and scheme UUID + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with the user does not have access to the scheme UUID + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with the user has access to the project UUID and the scheme UUID + Name: "test1_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: base request with info parameters + Name: "test1_06", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme deleted", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with broken scheme UUID + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with the user UUID (ignored) does not have access to the project UUID and scheme UUID + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with the user UUID (ignored) does not have access to the scheme UUID + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with the user UUID (ignored) has access to the project UUID and the scheme UUID + Name: "test2_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH2ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme deleted", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_schemeAccess(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "access"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with broken project UUID + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "access"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "access"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "access"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "access") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "access") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "access") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "access") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "access") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "access"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme access", + "result.scheme.server_ssh.address": "secret.net.google.com", + "result.scheme.server_ssh.port": float64(2206), + "result.scheme.server_ssh.alias": "onxzU5", + "result.scheme.server_ssh.password.login": "ubuntu6", + "result.scheme.server_ssh.password.password": "***", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_10", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "access") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme access", + "result.scheme.server_ssh.address": "127.0.0.4", + "result.scheme.server_ssh.port": float64(2207), + "result.scheme.server_ssh.alias": "JiepgT", + "result.scheme.server_ssh.password.login": "test", + "result.scheme.server_ssh.password.password": "***", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with broken project UUID + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "access"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "access"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "access"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "access") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "access") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with user UUID (ignored) + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "access") + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme access", + "result.scheme.server_ssh.address": "127.0.0.4", + "result.scheme.server_ssh.port": float64(2207), + "result.scheme.server_ssh.alias": "JiepgT", + "result.scheme.server_ssh.password.login": "test", + "result.scheme.server_ssh.password.password": "***", + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "access") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "access") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "access"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme access", + "result.scheme.server_ssh.address": "127.0.0.4", + "result.scheme.server_ssh.port": float64(2207), + "result.scheme.server_ssh.alias": "JiepgT", + "result.scheme.server_ssh.password.login": "test", + "result.scheme.server_ssh.password.password": "***", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_schemeActivity(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with broken project UUID + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.week.mon.0": float64(0), + "result.week.mon.12": float64(0), + "result.week.tue.1": float64(0), + "result.week.tue.11": float64(0), + "result.week.tue.13": float64(0), + "result.week.tue.23": float64(0), + "result.week.wed.2": float64(0), + "result.week.wed.10": float64(0), + "result.week.wed.14": float64(0), + "result.week.wed.22": float64(0), + "result.week.thu.3": float64(0), + "result.week.thu.9": float64(0), + "result.week.thu.15": float64(0), + "result.week.thu.21": float64(0), + "result.week.fri.4": float64(0), + "result.week.fri.8": float64(0), + "result.week.fri.16": float64(0), + "result.week.fri.20": float64(0), + "result.week.sat.5": float64(0), + "result.week.sat.7": float64(0), + "result.week.sat.17": float64(0), + "result.week.sat.19": float64(0), + "result.week.sun.6": float64(0), + "result.week.sun.18": float64(0), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: activity for now + Name: "test1_10", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity", "now"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.hour": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: activity for select hour (timestamp) + Name: "test1_11", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity", "1725885312000"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.hour": true, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: activity for owner UUID + Name: "test1_12", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.week.mon.6": float64(0), + "result.week.mon.18": float64(0), + "result.week.tue.5": float64(0), + "result.week.tue.7": float64(0), + "result.week.tue.17": float64(0), + "result.week.tue.19": float64(0), + "result.week.wed.4": float64(0), + "result.week.wed.8": float64(0), + "result.week.wed.16": float64(0), + "result.week.wed.20": float64(0), + "result.week.thu.3": float64(0), + "result.week.thu.9": float64(0), + "result.week.thu.15": float64(0), + "result.week.thu.21": float64(0), + "result.week.fri.2": float64(0), + "result.week.fri.10": float64(0), + "result.week.fri.14": float64(0), + "result.week.fri.22": float64(0), + "result.week.sat.1": float64(0), + "result.week.sat.11": float64(0), + "result.week.sat.13": float64(0), + "result.week.sat.23": float64(0), + "result.week.sun.0": float64(0), + "result.week.sun.12": float64(0), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: activity for now for owner UUID + Name: "test1_13", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity", "now") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.hour": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: activity for owner UUID select hour (timestamp) + Name: "test1_14", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity", "1725863712") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.hour": false, + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with broken project UUID + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.week.mon.6": float64(0), + "result.week.mon.18": float64(0), + "result.week.tue.5": float64(0), + "result.week.tue.7": float64(0), + "result.week.tue.17": float64(0), + "result.week.tue.19": float64(0), + "result.week.wed.4": float64(0), + "result.week.wed.8": float64(0), + "result.week.wed.16": float64(0), + "result.week.wed.20": float64(0), + "result.week.thu.3": float64(0), + "result.week.thu.9": float64(0), + "result.week.thu.15": float64(0), + "result.week.thu.21": float64(0), + "result.week.fri.2": float64(0), + "result.week.fri.10": float64(0), + "result.week.fri.14": float64(0), + "result.week.fri.22": float64(0), + "result.week.sat.1": float64(0), + "result.week.sat.11": float64(0), + "result.week.sat.13": float64(0), + "result.week.sat.23": float64(0), + "result.week.sun.0": float64(0), + "result.week.sun.12": float64(0), + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: activity for now + Name: "test2_10", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity", "now"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.hour": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: activity for select hour (timestamp) + Name: "test2_11", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity", "1725863712"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity", + "result.hour": false, + }, + RequestHeaders: userHeader, + }, + { // USER: activity for owner UUID + Name: "test2_12", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: activity for now for owner UUID + Name: "test2_13", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity", "now") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: activity for owner UUID select hour (timestamp) + Name: "test2_14", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity", "1725863712") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_updateSchemeActivity(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + createRepeatedValues := func(size int, value int32) []int32 { + repeatedValues := make([]int32, size) + for i := range repeatedValues { + repeatedValues[i] = value + } + return repeatedValues + } + + createActivityTable := func(values []int32, brokenDay string, brokenValues []int32) test.BodyTable { + activity := test.BodyTable{ + "mon": values, + "tue": values, + "wed": values, + "thu": values, + "fri": values, + "sat": values, + "sun": values, + } + + if brokenDay != "" && brokenValues != nil { + activity[brokenDay] = brokenValues + } + + return test.BodyTable{"activity": activity} + } + + validDayValues := createRepeatedValues(23, 0) + validDayValuesBody := createActivityTable(validDayValues, "", nil) + + brokenDayValues := createRepeatedValues(22, 1) + brokenDayValuesBody := createActivityTable(validDayValues, "mon", brokenDayValues) + + brokenDayValues2 := createRepeatedValues(23, 2) + brokenDayValues2Body2 := createActivityTable(validDayValues, "mon", brokenDayValues2) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with broken project UUID + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "access"), + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "access"), + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity"), + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: empty body request + Name: "test1_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.activity": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: broken body request (not all hours are transferred to monday (0-23)) + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 400, + RequestBody: brokenDayValuesBody, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "activity.mon": "value must contain at least 23 item(s)", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: broken body request (invalid values ​​passed to monday) + Name: "test1_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 400, + RequestBody: brokenDayValues2Body2, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "activity.mon[0]": "value must be in list [0, 1]", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: valid request + Name: "test1_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 200, + RequestBody: validDayValuesBody, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken user UUID + Name: "test1_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_11", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_12", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: valid request + Name: "test1_13", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: validDayValuesBody, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity updated", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with broken project UUID + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "access"), + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "access"), + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity"), + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: empty body request + Name: "test2_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.activity": "value is required", + }, + RequestHeaders: userHeader, + }, + { // USER: broken body request (not all hours are transferred to monday (0-23)) + Name: "test2_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity"), + StatusCode: 400, + RequestBody: brokenDayValuesBody, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "activity.mon": "value must contain at least 23 item(s)", + }, + }, + RequestHeaders: userHeader, + }, + { // USER: broken body request (invalid values ​​passed to monday) + Name: "test2_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity"), + StatusCode: 400, + RequestBody: brokenDayValues2Body2, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "activity.mon[0]": "value must be in list [0, 1]", + }, + }, + RequestHeaders: userHeader, + }, + { // USER: valid request + Name: "test2_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity"), + StatusCode: 200, + RequestBody: validDayValuesBody, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity updated", + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request with broken user UUID (ignored) + Name: "test2_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstFakeID, + StatusCode: 200, + RequestBody: validDayValuesBody, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme activity updated", + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_11", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_12", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + { // USER: valid request + Name: "test2_13", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "activity") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: validDayValuesBody, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_schemeFirewall(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request with broken project UUID + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "firewall"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: empty body request + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme firewall", + "result.country.total": float64(3), + "result.network.total": float64(2), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken user UUID + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: valid request + Name: "test1_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme firewall", + "result.country.total": float64(4), + "result.network.total": float64(3), + }, + RequestHeaders: adminHeader, + }, + + { // USER: request with broken project UUID + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "firewall"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: empty body request + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme firewall", + "result.country.total": float64(4), + "result.network.total": float64(3), + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken user UUID (ignored) + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Scheme firewall", + "result.country.total": float64(4), + "result.network.total": float64(3), + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_08", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: adminHeader, + }, + { // USER: valid request + Name: "test2_09", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallNotFound, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addSchemeFirewall(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + genSchemeFirewallData := func(scheme, value string) test.BodyTable { + data := test.BodyTable{ + "owner_id": test.ConstFakeID, + "project_id": test.ConstFakeID, + "scheme_id": test.ConstFakeID, + } + + switch scheme { + case "country": + data["country_code"] = value + case "network": + data["network"] = value + } + return data + } + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: empty request + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "record": "exactly one field is required in oneof", + }, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(200), + "message": "Country added", + "result.country_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with double + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_04", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genSchemeFirewallData("network", "192.168.20.20"), + Body: test.BodyTable{ + "code": float64(200), + "message": "Network added", + "result.network_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with double + Name: "test1_05", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("network", "192.168.20.20"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID + Name: "test1_06", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_07", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_08", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_09", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken user UUID + Name: "test1_10", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_11", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_12", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: valid request + Name: "test1_13", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: genSchemeFirewallData("country", "CA"), + Body: test.BodyTable{ + "code": float64(200), + "message": "Country added", + "result.country_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: valid request + Name: "test1_14", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: genSchemeFirewallData("network", "192.168.20.20"), + Body: test.BodyTable{ + "code": float64(200), + "message": "Network added", + "result.network_id": "*", + }, + RequestHeaders: adminHeader, + }, + + { // USER: empty request + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": map[string]any{ + "record": "exactly one field is required in oneof", + }, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(200), + "message": "Country added", + "result.country_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: request with double + Name: "test2_03", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_04", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genSchemeFirewallData("network", "192.168.20.30"), + Body: test.BodyTable{ + "code": float64(200), + "message": "Network added", + "result.network_id": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: request with double + Name: "test2_05", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("network", "192.168.20.30"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID + Name: "test2_06", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_07", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_08", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall"), + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_09", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken user UUID + Name: "test2_10", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_11", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_12", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: valid request + Name: "test2_13", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("country", "ES"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + { // USER: valid request + Name: "test2_14", + Method: http.MethodPost, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 400, + RequestBody: genSchemeFirewallData("network", "192.168.20.30"), + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": trace.MsgFailedToAdd, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_updateSchemeFirewall(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + genRequestBody := func(scheme string, status bool) test.BodyTable { + data := test.BodyTable{ + "owner_id": test.ConstFakeID, + "project_id": test.ConstFakeID, + "scheme_id": test.ConstFakeID, + } + + switch scheme { + case "country": + data["country"] = status + case "network": + data["network"] = status + } + return data + } + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + + { // ADMIN: request + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.status": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: update status list for country + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(200), + "message": "Record updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: update status list for network + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genRequestBody("network", true), + Body: test.BodyTable{ + "code": float64(200), + "message": "Record updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "firewall"), + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID + Name: "test1_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID + Name: "test1_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall"), + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken user UUID + Name: "test1_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_11", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(200), + "message": "Record updated", + }, + RequestHeaders: adminHeader, + }, + + { // USER: request + Name: "test2_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.status": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: update status list for country + Name: "test2_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(200), + "message": "Record updated", + }, + RequestHeaders: userHeader, + }, + { // USER: update status list for network + Name: "test2_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 200, + RequestBody: genRequestBody("network", true), + Body: test.BodyTable{ + "code": float64(200), + "message": "Record updated", + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_04", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "firewall"), + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID + Name: "test2_05", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "firewall"), + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID + Name: "test2_06", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall"), + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_07", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken user UUID + Name: "test2_08", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstFakeID, + StatusCode: 200, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(200), + "message": "Record updated", + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_09", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_10", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_11", + Method: http.MethodPatch, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall") + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + RequestBody: genRequestBody("country", true), + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgFirewallListNotFound, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_deleteSchemeFirewall(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request + Name: "test1_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "network"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + { // ADMIN: remove country + Name: "test1_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstAdminSchemeSSH1FrwCnt1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Country deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: remove network + Name: "test1_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "network", test.ConstAdminSchemeSSH1FrwNtw1ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Network deleted", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_06", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "network", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgNetworkNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID + Name: "test1_07", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken scheme UUID + Name: "test1_08", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstFakeID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID and scheme UUID + Name: "test1_09", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken project UUID, scheme UUID and user UUID + Name: "test1_10", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall", "country", test.ConstFakeID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with broken user UUID + Name: "test1_11", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstFakeID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_12", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstFakeID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request + Name: "test1_13", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "country", test.ConstUserSchemeSSH1FrwCnt1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: valid request + Name: "test1_14", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "country", test.ConstUserSchemeSSH1FrwCnt1ID) + "?owner_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Country deleted", + }, + RequestHeaders: adminHeader, + }, + + { // USER: remove country + Name: "test2_01", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "country", test.ConstUserSchemeSSH1FrwCnt2ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Country deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: remove network + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "network", test.ConstUserSchemeSSH1FrwNtw2ID), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Network deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "network", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgNetworkNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID + Name: "test2_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstUserSchemeSSH1ID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken scheme UUID + Name: "test2_06", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstFakeID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID and scheme UUID + Name: "test2_07", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall", "country", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken project UUID, scheme UUID and user UUID + Name: "test2_08", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstFakeID, test.ConstFakeID, "firewall", "country", test.ConstFakeID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request with broken user UUID + Name: "test2_09", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstUserSchemeSSH1ID, "firewall", "country", test.ConstFakeID) + "?owner_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_10", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstFakeID) + "?owner_id=" + test.ConstUserID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: request + Name: "test2_11", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstUserProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstAdminSchemeSSH1FrwCnt1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + { // USER: valid request + Name: "test2_12", + Method: http.MethodDelete, + Path: test.PathGluing(pathSchemes, test.ConstAdminProject1ID, test.ConstAdminSchemeSSH1ID, "firewall", "country", test.ConstAdminSchemeSSH1FrwCnt1ID) + "?owner_id=" + test.ConstAdminID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgCountryNotFound, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/scheme/user_test.go b/api/scheme/user_test.go new file mode 100644 index 00000000..8a4e7c7e --- /dev/null +++ b/api/scheme/user_test.go @@ -0,0 +1,293 @@ +package scheme + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/trace" + "github.com/werbot/werbot/internal/utils/test" +) + +func TestHandler_userSchemes(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(7), + "result.total.300": float64(2), + "result.total.400": float64(2), + "result.total.500": float64(0), + "result.total.600": float64(0), + "result.schemes": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: limit + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user") + "?limit=5", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(7), + "result.total.300": float64(2), + "result.total.400": float64(2), + "result.total.500": float64(0), + "result.total.600": float64(0), + "result.schemes.0.active": "*", + "result.schemes.0.alias": "*", + "result.schemes.0.auth_method": "*", + "result.schemes.0.project_id": "*", + "result.schemes.0.scheme_type": "*", + "result.schemes.0.title": "*", + "result.schemes.5": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "desktop"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(7), + "result.total.300": float64(2), + "result.total.400": float64(2), + "result.total.500": float64(0), + "result.total.600": float64(0), + "result.schemes.0": "*", + "result.schemes.1": "*", + "result.schemes.2": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: desktop schemes with limit + Name: "test1_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "desktop") + "?limit=1", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(7), + "result.total.300": float64(2), + "result.total.400": float64(2), + "result.total.500": float64(0), + "result.total.600": float64(0), + "result.schemes.0": "*", + "result.schemes.1": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with fake user UUID + Name: "test1_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user") + "?user_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with real user UUID + Name: "test1_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user") + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes": "*", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: default request with real user UUID select scheme + Name: "test1_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "desktop") + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes.2": nil, + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test0_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "test"), + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: limit + Name: "test2_02", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user") + "?limit=5", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes.0.active": "*", + "result.schemes.0.alias": "*", + "result.schemes.0.auth_method": "*", + "result.schemes.0.project_id": "*", + "result.schemes.0.scheme_type": "*", + "result.schemes.0.title": "*", + "result.schemes.5": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_03", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "desktop"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes.0": "*", + "result.schemes.1": "*", + "result.schemes.2": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: desktop schemes with limit + Name: "test2_04", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "desktop") + "?limit=1", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes.0": "*", + "result.schemes.1": nil, + }, + RequestHeaders: userHeader, + }, + { // USER: default request with fake user UUID + Name: "test2_05", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user") + "?user_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": trace.MsgSchemeNotFound, + }, + RequestHeaders: adminHeader, + }, + { // USER: default request with real user UUID + Name: "test2_06", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user") + "?user_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes": "*", + }, + RequestHeaders: userHeader, + }, + { // USER: default request with real user UUID select scheme + Name: "test2_07", + Method: http.MethodGet, + Path: test.PathGluing(pathSchemes, "user", "desktop") + "?user_id=" + test.ConstAdminID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User schemes", + "result.total.100": float64(5), + "result.total.200": float64(10), + "result.total.300": float64(2), + "result.total.400": float64(3), + "result.total.500": float64(8), + "result.total.600": float64(2), + "result.schemes.2": nil, + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/system/info_test.go b/api/system/info_test.go new file mode 100644 index 00000000..7dea251f --- /dev/null +++ b/api/system/info_test.go @@ -0,0 +1,173 @@ +package system + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/utils/test" +) + +func TestHandler_update(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathSystemUpdate, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: pathSystemUpdate, + StatusCode: 200, + Body: test.BodyTable{"code": float64(200), "message": "Updates"}, + RequestHeaders: adminHeader, + }, + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: pathSystemUpdate, + StatusCode: 404, + Body: test.BodyNotFound, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_info(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathSystemInfo, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: pathSystemInfo, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Short", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: request with show global information + Name: "test1_02", + Method: http.MethodGet, + Path: pathSystemInfo + "?user_id=" + test.ConstFakeID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Short", + "result.users": float64(22), + "result.projects": float64(51), + "result.schemes": float64(147), + }, RequestHeaders: adminHeader, + }, + { // ADMIN: request with user UUID + Name: "test1_03", + Method: http.MethodGet, + Path: pathSystemInfo + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Short", + "result.projects": float64(3), + "result.schemes": float64(68), + }, RequestHeaders: adminHeader, + }, + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: pathSystemInfo, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Short", + "result.projects": float64(3), + "result.schemes": float64(68), + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters with fake user UUID + Name: "test2_02", + Method: http.MethodGet, + Path: pathSystemInfo + "?user_id=" + test.ConstFakeID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Short", + "result.projects": float64(3), + "result.schemes": float64(68), + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_version(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathSystemVersion, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: request without parameters + Name: "test1_01", + Method: http.MethodGet, + Path: pathSystemVersion, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Apps version", + "result.api": "0.0.1 (00000000)", + }, + RequestHeaders: adminHeader, + }, + { // USER: request without parameters + Name: "test2_01", + Method: http.MethodGet, + Path: pathSystemVersion, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Apps version", + "result.api": "0.0.1 (00000000)", + }, + RequestHeaders: userHeader, + }, + { // USER: request without parameters + Name: "test2_02", + Method: http.MethodGet, + Path: pathSystemVersion, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Apps version", + "result.api": "0.0.1 (00000000)", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/system/routes_test.go b/api/system/routes_test.go new file mode 100644 index 00000000..6375ab20 --- /dev/null +++ b/api/system/routes_test.go @@ -0,0 +1,28 @@ +package system + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const ( + pathSystem = "/v1/system" + pathSystemInfo = pathSystem + "/info" + pathSystemUpdate = pathSystem + "/update" + pathSystemVersion = pathSystem + "/version" + pathSystemMyIP = pathSystem + "/myip" + pathSystemCountries = pathSystem + "/countries" +) + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/system/utility_test.go b/api/system/utility_test.go new file mode 100644 index 00000000..a0bb5032 --- /dev/null +++ b/api/system/utility_test.go @@ -0,0 +1,111 @@ +package system + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/utils/test" +) + +func TestHandler_myIP(t *testing.T) { + app, teardownTestCase, adminHeader, _ := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathSystemMyIP, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "IP", + "result": "0.0.0.0", + }, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: pathSystemMyIP, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "IP", + "result": "0.0.0.0", + }, + RequestHeaders: adminHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_countries(t *testing.T) { + app, teardownTestCase, adminHeader, _ := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathSystemVersion, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: pathSystemCountries, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.name": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: pathSystemCountries + "?name=be", + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.name": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: pathSystemCountries + "?name=bel", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Countries", + "result.countries.0.code": "BY", + "result.countries.0.name": "Belarus", + "result.countries.1.code": "BE", + "result.countries.1.name": "Belgium", + "result.countries.2.code": "BZ", + "result.countries.2.name": "Belize", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodGet, + Path: pathSystemCountries + "?name=test", + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: adminHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/api/user/routes_test.go b/api/user/routes_test.go new file mode 100644 index 00000000..17d7ed6c --- /dev/null +++ b/api/user/routes_test.go @@ -0,0 +1,21 @@ +package user + +import ( + "testing" + + "github.com/werbot/werbot/api/auth" + "github.com/werbot/werbot/internal/utils/test" +) + +const pathUsers = "/v1/users" + +func setupTest(t *testing.T) (*test.APIHandler, func(t *testing.T), map[string]string, map[string]string) { + app, teardownTestCase := test.API(t) + auth.New(app.Handler).Routes() + New(app.Handler).Routes() + app.AddRoute404() + + adminHeader, userHeader := app.TestUserAuth() + + return app, teardownTestCase, adminHeader, userHeader +} diff --git a/api/user/user_test.go b/api/user/user_test.go new file mode 100644 index 00000000..79b629f5 --- /dev/null +++ b/api/user/user_test.go @@ -0,0 +1,904 @@ +package user + +import ( + "net/http" + "testing" + + "github.com/werbot/werbot/internal/utils/test" +) + +func TestHandler_users(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: test.PathGluing(pathUsers, "list"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: test.PathGluing(pathUsers, "list"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Users", + "result.total": float64(22), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: test.PathGluing(pathUsers, "list") + "?limit=2&offset=0", + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "Users", + "result.total": float64(22), + "result.users.0": "*", + "result.users.1": "*", + "result.users.2": nil, + }, + RequestHeaders: adminHeader, + }, + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathUsers, "list"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_user(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodGet, + Path: pathUsers, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodGet, + Path: pathUsers, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User", + "result.user_id": test.ConstAdminID, + "result.alias": "admin", + "result.name": "Penny", + "result.surname": "Hoyle", + "result.email": "admin@werbot.net", + "result.active": true, + "result.confirmed": true, + "result.role": float64(3), + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": "*", + "result.created_at": "*", + "result.projects_count": float64(11), + "result.schemes_count": float64(79), + "result.keys_count": float64(12), + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodGet, + Path: pathUsers + "?user_id=" + test.ConstFakeID, + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodGet, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User", + "result.user_id": test.ConstUserID, + "result.alias": "user", + "result.name": "Carly", + "result.surname": "Bender", + "result.email": "user@werbot.net", + "result.active": true, + "result.confirmed": true, + "result.role": float64(1), + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + "result.projects_count": float64(3), + "result.schemes_count": float64(68), + "result.keys_count": float64(2), + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_01", + Method: http.MethodGet, + Path: test.PathGluing(pathUsers), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User", + "result.user_id": test.ConstUserID, + "result.alias": "user", + "result.name": "Carly", + "result.surname": "Bender", + "result.email": "user@werbot.net", + "result.active": true, + "result.confirmed": true, + "result.role": float64(1), + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + "result.projects_count": float64(3), + "result.schemes_count": float64(68), + "result.keys_count": float64(2), + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_02", + Method: http.MethodGet, + Path: pathUsers + "?user_id=" + test.ConstFakeID, + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User", + "result.user_id": test.ConstUserID, + "result.alias": "user", + "result.name": "Carly", + "result.surname": "Bender", + "result.email": "user@werbot.net", + "result.active": true, + "result.confirmed": true, + "result.role": float64(1), + "result.locked_at": nil, + "result.archived_at": nil, + "result.updated_at": nil, + "result.created_at": "*", + "result.projects_count": float64(3), + "result.schemes_count": float64(68), + "result.keys_count": float64(2), + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_addUser(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPost, + Path: pathUsers, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodPost, + Path: pathUsers, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value is required", + "result.email": "value is required", + "result.name": "value is required", + "result.surname": "value is required", + "result.password": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodPost, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "az", + "email": "az", + "name": "az", + "surname": "az", + "password": "az", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value length must be at least 3 characters", + "result.email": "must be a valid email", + "result.name": "value length must be at least 3 characters", + "result.surname": "value length must be at least 3 characters", + "result.password": "value length must be at least 8 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: double + Name: "test1_03", + Method: http.MethodPost, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "alias", + "email": "user@werbot.net", + "name": "Name", + "surname": "Surname", + "password": "password", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": "Failed to add", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPost, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "alias", + "email": "user@mail.com", + "name": "Name", + "surname": "Surname", + "password": "password", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User added", + "result.user_id": "*", + }, + RequestHeaders: adminHeader, + }, + { // USER: + Name: "test2_01", + Method: http.MethodPost, + Path: pathUsers, + StatusCode: 404, + RequestBody: test.BodyTable{ + "alias": "alias", + "email": "user@mail.com", + "name": "Name", + "surname": "Surname", + "password": "password", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_updateUser(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "test": "az", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "alias": "az", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.alias": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_04", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": "az", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.email": "must be a valid email", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_05", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "name": "az", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.name": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_06", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "surname": "az", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.surname": "value length must be at least 3 characters", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_07", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "user_id": test.ConstFakeID, + "alias": "alias", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_08", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "email": "user@email.com", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_09", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "name": "name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_10", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "surname": "surname", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_11", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "confirmed": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_12", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_13", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstFakeID, + StatusCode: 404, + RequestBody: test.BodyTable{ + "alias": "alias", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_14", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "alias": "alias", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_15", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "email": "user@email.com", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_16", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "name": "name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_17", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "surname": "surname", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_18", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "confirmed": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_19", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstUserID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: adminHeader, + }, + + { // USER: + Name: "test2_1", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "name": "New Name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_2", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 200, + RequestBody: test.BodyTable{ + "surname": "New Surname", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_3", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "email": "new@mail.com", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_4", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "confirmed": true, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_5", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "active": true, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: + Name: "test2_6", + Method: http.MethodPatch, + Path: pathUsers, + StatusCode: 400, + RequestBody: test.BodyTable{ + "archive": true, + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.setting": "exactly one field is required in oneof", + }, + RequestHeaders: userHeader, + }, + { // USER: ignored user_id + Name: "test2_7", + Method: http.MethodPatch, + Path: pathUsers + "?user_id=" + test.ConstFakeID, + StatusCode: 200, + RequestBody: test.BodyTable{ + "name": "New Name", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "User updated", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_deleteUser(t *testing.T) { + app, teardownTestCase, adminHeader, userHeader := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request: step 1 + Name: "test0_01", + Method: http.MethodPost, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // unauthorized request: step 2 + Name: "test0_02", + Method: http.MethodDelete, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: step 1 + Name: "test1_01", + Method: http.MethodPost, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.request": "exactly one field is required in oneof", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: step 1, bad password + Name: "test1_02", + Method: http.MethodPost, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 404, + RequestBody: test.BodyTable{ + "password": "password", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: step 1, real password + // The administrator cannot be deleted!!! + Name: "test1_03", + Method: http.MethodPost, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 404, + RequestBody: test.BodyTable{ + "password": "admin@werbot.com", + }, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: step 1, real password for delete oth + // The administrator cannot be deleted!!! + Name: "test1_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathUsers, "delete", "3c818d7c-72f3-4518-8eaa-755585192f21"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + }, + RequestHeaders: adminHeader, + }, + + { // USER: step 1, bad password + Name: "test2_01", + Method: http.MethodPost, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "password": "password", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": "Password is not valid", + }, + RequestHeaders: userHeader, + }, + { // USER: step 1, real password + Name: "test2_02", + Method: http.MethodPost, + Path: test.PathGluing(pathUsers, "delete"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "password": "user@werbot.net", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Request for delete", + "result": "An email with instructions to delete your profile has been sent to your email", + }, + RequestHeaders: userHeader, + }, + { // USER: step 2, bad token + Name: "test2_03", + Method: http.MethodDelete, + Path: test.PathGluing(pathUsers, "delete", test.ConstFakeID), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + { // USER: step 2, real token + Name: "test2_04", + Method: http.MethodDelete, + Path: test.PathGluing(pathUsers, "delete", "8c7c9b35-1c3e-4679-ab2d-3e176a2b73d9"), + StatusCode: 200, + Body: test.BodyTable{ + "code": float64(200), + "message": "User deleted", + }, + RequestHeaders: userHeader, + }, + { // USER: step 2, disabled token + Name: "test2_05", + Method: http.MethodDelete, + Path: test.PathGluing(pathUsers, "delete", "0fcd88b3-8abb-4eb1-b96c-e0e49964cbca"), + StatusCode: 404, + Body: test.BodyTable{ + "code": float64(404), + "message": "Not Found", + "result": "Not found", + }, + RequestHeaders: userHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} + +func TestHandler_updatePassword(t *testing.T) { + t.Setenv("PASSWORD_HASH_COST", "1") + + app, teardownTestCase, adminHeader, _ := setupTest(t) + defer teardownTestCase(t) + + testTable := []test.APITable{ + { // unauthorized request + Name: "test0_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathUsers, "password"), + StatusCode: 401, + Body: test.BodyUnauthorized, + }, + { // ADMIN: + Name: "test1_01", + Method: http.MethodPatch, + Path: test.PathGluing(pathUsers, "password"), + StatusCode: 400, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result.new_password": "value is required", + "result.old_password": "value is required", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_02", + Method: http.MethodPatch, + Path: test.PathGluing(pathUsers, "password"), + StatusCode: 400, + RequestBody: test.BodyTable{ + "old_password": "12345678", + "new_password": "12345678", + }, + Body: test.BodyTable{ + "code": float64(400), + "message": "Bad Request", + "result": "Password is not valid", + }, + RequestHeaders: adminHeader, + }, + { // ADMIN: + Name: "test1_03", + Method: http.MethodPatch, + Path: test.PathGluing(pathUsers, "password"), + StatusCode: 200, + RequestBody: test.BodyTable{ + "old_password": "admin@werbot.net", + "new_password": "123456789", + }, + Body: test.BodyTable{ + "code": float64(200), + "message": "Password updated", + }, + RequestHeaders: adminHeader, + }, + } + + test.RunCaseAPITests(t, app, testTable) +} diff --git a/internal/grpc/account/account_test.go b/internal/grpc/account/account_test.go index b31c7402..845d3278 100644 --- a/internal/grpc/account/account_test.go +++ b/internal/grpc/account/account_test.go @@ -4,84 +4,38 @@ import ( "context" "testing" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc" - - accountpb "github.com/werbot/werbot/internal/grpc/account/proto" + accountpb "github.com/werbot/werbot/internal/grpc/account/proto/account" "github.com/werbot/werbot/internal/utils/test" + "google.golang.org/grpc/codes" ) -type testSetup struct { - ctx context.Context - grpc *grpc.ClientConn -} - -func setupTest(t *testing.T) (testSetup, func(t *testing.T)) { - ctx := context.Background() - - // Initialize postgres connection - postgres, err := test.Postgres(t, "../../../migration", "../../../fixtures/migration") - if err != nil { - t.Fatalf("failed to initialize Postgres: %v", err) - } - - // Initialize gRPC connection - grpc, err := test.GRPC(ctx, t, postgres.Conn(), nil) - if err != nil { - t.Fatalf("failed to initialize gRPC: %v", err) - } - - return testSetup{ - ctx: ctx, - grpc: grpc.ClientConn, - }, func(t *testing.T) { - postgres.Close() - grpc.Close() - } -} - func Test_account_AccountIDByLogin(t *testing.T) { - t.Parallel() - setup, teardownTestCase := setupTest(t) + setup, teardownTestCase := test.GRPC(t) defer teardownTestCase(t) - testCases := []struct { - name string - req *accountpb.AccountIDByLogin_Request - resp *accountpb.AccountIDByLogin_Response - respErr string - }{ + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := accountpb.NewAccountHandlersClient(setup) + return a.AccountIDByLogin(ctx, req.(*accountpb.AccountIDByLogin_Request)) + } + + testTable := []test.GRPCTable{ { - name: "test", - req: &accountpb.AccountIDByLogin_Request{ + Name: "test0_01", + Request: &accountpb.AccountIDByLogin_Request{ Login: "admin", Fingerprint: "b6:07:6a:ef:82:e3:73:47:56:69:3f:3d:c7:d7:6f:23", }, - resp: &accountpb.AccountIDByLogin_Response{ - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - }, - }, - { - name: "test2", - req: &accountpb.AccountIDByLogin_Request{ - Login: "user", - Fingerprint: "b6:07:6a:ef:82:e3:73:47:56:69:3f:3d:c7:d7:6f:23", + //Response: &accountpb.AccountIDByLogin_Response{ + // UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + //}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "client_ip": "value is empty, which is not a valid IP address", + }, }, - resp: &accountpb.AccountIDByLogin_Response{}, - respErr: "rpc error: code = NotFound desc = Not found", }, } - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - a := accountpb.NewAccountHandlersClient(setup.grpc) - response, err := a.AccountIDByLogin(setup.ctx, tt.req) - if err != nil { - assert.EqualError(t, err, tt.respErr) - return - } - assert.NoError(t, err) - assert.Equal(t, tt.resp.UserId, response.UserId) - }) - } + test.RunCaseGRPCTests(t, handler, testTable) } diff --git a/internal/grpc/event/event_test.go b/internal/grpc/event/event_test.go index fc75658a..b9ec8cf9 100644 --- a/internal/grpc/event/event_test.go +++ b/internal/grpc/event/event_test.go @@ -4,449 +4,519 @@ import ( "context" "testing" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc" - - eventpb "github.com/werbot/werbot/internal/grpc/event/proto" + eventpb "github.com/werbot/werbot/internal/grpc/event/proto/event" "github.com/werbot/werbot/internal/utils/test" + "github.com/werbot/werbot/pkg/uuid" + "google.golang.org/grpc/codes" ) -type testSetup struct { - ctx context.Context - grpc *grpc.ClientConn -} - -func setupTest(t *testing.T) (testSetup, func(t *testing.T)) { - ctx := context.Background() - - postgres, err := test.Postgres(t, "../../../migration", "../../../fixtures/migration") - if err != nil { - t.Error(err) - } - - grpc, err := test.GRPC(ctx, t, postgres.Conn(), nil) - if err != nil { - t.Error(err) - } - - return testSetup{ - ctx: ctx, - grpc: grpc.ClientConn, - }, func(t *testing.T) { - postgres.Close() - grpc.Close() - } -} - func Test_Events(t *testing.T) { - // t.Parallel() - setup, teardownTestCase := setupTest(t) + setup, teardownTestCase := test.GRPC(t) defer teardownTestCase(t) - testCases := []struct { - name string - req *eventpb.Events_Request - resp *eventpb.Events_Response - respErr string - }{ - { - name: "request without parameters", - req: &eventpb.Events_Request{}, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", - }, + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := eventpb.NewEventHandlersClient(setup) + return a.Events(ctx, req.(*eventpb.Events_Request)) + } - // profile events + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &eventpb.Events_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is required", + "id": "exactly one field is required in oneof", + }, + }, + }, { - name: "profile has no events", - req: &eventpb.Events_Request{ + Name: "test0_02", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProfileId{ - ProfileId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", + ProfileId: test.ConstUserID, }, }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is required", + }, }, }, { - name: "list of all profile events", - req: &eventpb.Events_Request{ + Name: "test0_03", + Request: &eventpb.Events_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Events_Request_ProfileId{ - ProfileId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + ProfileId: "test", }, }, - resp: &eventpb.Events_Response{ - Total: 2, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "profile_id": "value must be a valid UUID", + }, }, }, - { - name: "list of all profile events with limit", - req: &eventpb.Events_Request{ + + { // list of all admin profile events + Name: "test0_04", + Request: &eventpb.Events_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Events_Request_ProfileId{ - ProfileId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + ProfileId: test.ConstAdminID, + }, + }, + Response: test.BodyTable{ + "total": float64(2), + "records.0": "*", + "records.1": "*", + "records.2": nil, + }, + }, + { // list of all profile events with limit + Name: "test0_05", + Request: &eventpb.Events_Request{ + UserId: test.ConstAdminID, + Id: &eventpb.Events_Request_ProfileId{ + ProfileId: test.ConstAdminID, }, Limit: 1, }, - resp: &eventpb.Events_Response{ - Total: 2, + Response: test.BodyTable{ + "total": float64(2), + "records.0": "*", + "records.1": nil, }, }, - { - name: "non-existent profile UUID", - req: &eventpb.Events_Request{ + + { // "non-existent profile UUID" + Name: "test0_06", + Request: &eventpb.Events_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Events_Request_ProfileId{ ProfileId: "00000000-0000-0000-0000-000000000000", }, }, - resp: &eventpb.Events_Response{}, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Profile not found", + }, }, // project events - { - name: "owner: project has no events", - req: &eventpb.Events_Request{ + { // "owner: project has no events" + Name: "test0_07", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "ca7e65a4-76ea-4802-9f4f-3518a3416985", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Project not found", }, }, - { - name: "guest: project has no events", - req: &eventpb.Events_Request{ + + { // guest: project has no events + Name: "test0_08", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "ca7e65a4-76ea-4802-9f4f-3518a3416985", }, UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Project not found", }, }, - { - name: "owner: list of all project events", - req: &eventpb.Events_Request{ + { // owner: list of all project events + Name: "test0_09", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "26060c68-5a06-4a57-b87a-be0f1e787157", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Events_Response{ - Total: 2, + Response: test.BodyTable{ + "total": float64(2), + "records.0": "*", + "records.1": "*", + "records.2": nil, }, }, - { - name: "guest: list of all project events", - req: &eventpb.Events_Request{ + { // guest: list of all project events + Name: "test0_10", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "26060c68-5a06-4a57-b87a-be0f1e787157", }, UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Project not found", }, }, - { - name: "owner: list of all project events with limit", - req: &eventpb.Events_Request{ + { // owner: list of all project events with limit + Name: "test0_11", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "26060c68-5a06-4a57-b87a-be0f1e787157", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", Limit: 1, }, - resp: &eventpb.Events_Response{ - Total: 2, + Response: test.BodyTable{ + "total": float64(2), + "records.0": "*", + "records.1": nil, }, }, - { - name: "non-existent project UUID", - req: &eventpb.Events_Request{ + { // non-existent project UUID + Name: "test0_12", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "00000000-0000-0000-0000-000000000000", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Events_Response{}, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Project not found", + }, }, - { - name: "project events no custom UUID passed", - req: &eventpb.Events_Request{ + { // project events no custom UUID passed + Name: "test0_13", + Request: &eventpb.Events_Request{ Id: &eventpb.Events_Request_ProjectId{ ProjectId: "00000000-0000-0000-0000-000000000000", }, }, - resp: &eventpb.Events_Response{}, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is required", + }, + }, }, // server events - { - name: "owner: server has no events", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "ddd084a5-7d91-4796-a133-feab4e653721", + { // owner: server has no events + Name: "test0_14", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "ddd084a5-7d91-4796-a133-feab4e653721", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", }, }, - { - name: "guest: server has no events", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "ca7e65a4-76ea-4802-9f4f-3518a3416985", + { // guest: server has no events + Name: "test0_15", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "ca7e65a4-76ea-4802-9f4f-3518a3416985", }, UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", }, }, - { - name: "owner: list of all server events", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "0c3a8869-6fc0-4666-bf60-15475473392a", + { // owner: list of all server events + Name: "test0_16", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "0c3a8869-6fc0-4666-bf60-15475473392a", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Events_Response{ - Total: 11, + Response: test.BodyTable{ + "total": float64(11), }, }, - { - name: "guest: list of all server events", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "0c3a8869-6fc0-4666-bf60-15475473392a", + { // guest: list of all server events + Name: "test0_17", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "0c3a8869-6fc0-4666-bf60-15475473392a", }, UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", }, - resp: &eventpb.Events_Response{ - Total: 0, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", }, }, - { - name: "owner: list of all server events with limit", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "0c3a8869-6fc0-4666-bf60-15475473392a", + { // owner: list of all server events with limit + Name: "test0_18", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "0c3a8869-6fc0-4666-bf60-15475473392a", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", Limit: 1, }, - resp: &eventpb.Events_Response{ - Total: 11, + Response: test.BodyTable{ + "total": float64(11), + "records.0": "*", + "records.1": nil, }, }, - { - name: "non-existent server UUID", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "00000000-0000-0000-0000-000000000000", + { // non-existent server UUID + Name: "test0_19", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "00000000-0000-0000-0000-000000000000", }, UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Events_Response{}, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", + }, }, - { - name: "server event no custom UUID passed", - req: &eventpb.Events_Request{ - Id: &eventpb.Events_Request_ServerId{ - ServerId: "00000000-0000-0000-0000-000000000000", + { // server event no custom UUID passed + Name: "test0_20", + Request: &eventpb.Events_Request{ + Id: &eventpb.Events_Request_SchemeId{ + SchemeId: "00000000-0000-0000-0000-000000000000", + }, + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is required", }, }, - resp: &eventpb.Events_Response{}, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", }, } - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - a := eventpb.NewEventHandlersClient(setup.grpc) - response, err := a.Events(setup.ctx, tt.req) - if err != nil { - assert.EqualError(t, err, tt.respErr) - return - } - assert.NoError(t, err) - assert.Equal(t, tt.resp.GetTotal(), response.GetTotal()) - }) - } + test.RunCaseGRPCTests(t, handler, testTable) } func Test_Event(t *testing.T) { - // t.Parallel() - setup, teardownTestCase := setupTest(t) + setup, teardownTestCase := test.GRPC(t) defer teardownTestCase(t) - testCases := []struct { - name string - req *eventpb.Event_Request - resp *eventpb.Event_Response - respErr string - }{ + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := eventpb.NewEventHandlersClient(setup) + return a.Event(ctx, req.(*eventpb.Event_Request)) + } + + testTable := []test.GRPCTable{ { - name: "request without parameters", - req: &eventpb.Event_Request{}, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", + Name: "test0_01", + Request: &eventpb.Event_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is required", + "id": "exactly one field is required in oneof", + }, + }, }, - - // profile event { - name: "owner: show profile event by UUID", - req: &eventpb.Event_Request{ + Name: "test0_02", + Request: &eventpb.Event_Request{ + UserId: test.ConstFakeID, + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "id": "exactly one field is required in oneof", + }, + }, + }, + { + Name: "test0_03", + Request: &eventpb.Event_Request{ + UserId: test.ConstFakeID, Id: &eventpb.Event_Request_ProfileId{ - ProfileId: "59fab0fa-8f0a-4065-8863-0dae40166015", + ProfileId: test.ConstFakeID, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Event_Response{ - Ip: "2001:db8:85a3::8a2e:370:7334", - Event: 9, - MetaData: []byte("{}"), + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", }, }, + + // profile event { - name: "owner: show profile event by fake UUID", - req: &eventpb.Event_Request{ + Name: "test1_01", + Request: &eventpb.Event_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Event_Request_ProfileId{ - ProfileId: "00000000-0000-0000-0000-000000000000", + ProfileId: test.ConstFakeID, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - respErr: "rpc error: code = NotFound desc = Not found", + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", + }, }, { - name: "guest: show profile event by UUID", - req: &eventpb.Event_Request{ + Name: "test1_02", + Request: &eventpb.Event_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Event_Request_ProfileId{ - ProfileId: "59fab0fa-8f0a-4065-8863-0dae40166015", + ProfileId: test.ConstAdminProfileEventID, }, - UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", }, - respErr: "rpc error: code = NotFound desc = Not found", + Response: test.BodyTable{ + "profile_id": test.ConstAdminProfileEventID, + "session_id": "98e3ddfc-dab0-4d4e-b48e-ab1717acae8b", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:35.0) Gecko/20100101 Firefox/35.", + "ip": "2001:db8:85a3::8a2e:370:7334", + "event": float64(9), + "section": float64(1), + "meta_data": "e30=", + "created_at": "*", + }, }, // project event { - name: "owner: show project event by UUID", - req: &eventpb.Event_Request{ + Name: "test2_01", + Request: &eventpb.Event_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Event_Request_ProjectId{ - ProjectId: "163dee10-2a74-4436-9507-65a97a711ba8", + ProjectId: test.ConstFakeID, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Event_Response{ - Ip: "192.168.0.1", - Event: 1, - MetaData: []byte("{}"), + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", }, }, { - name: "owner: show project event by fake UUID", - req: &eventpb.Event_Request{ + Name: "test2_02", + Request: &eventpb.Event_Request{ + UserId: test.ConstAdminID, Id: &eventpb.Event_Request_ProjectId{ - ProjectId: "00000000-0000-0000-0000-000000000000", + ProjectId: test.ConstAdminProjectEventID, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - respErr: "rpc error: code = NotFound desc = Not found", - }, - { - name: "guest: show project event by UUID", - req: &eventpb.Event_Request{ - Id: &eventpb.Event_Request_ProjectId{ - ProjectId: "163dee10-2a74-4436-9507-65a97a711ba8", - }, - UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", + Response: test.BodyTable{ + "project_id": test.ConstAdminEventProjectID, + "session_id": "98e3ddfc-dab0-4d4e-b48e-ab1717acae8b", + "user_agent": "Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; KFJWI Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.68 like Chrome/39.0.2171.93 Safari/537.36", + "ip": "192.168.0.1", + "event": float64(1), + "section": float64(1), + "meta_data": "e30=", + "created_at": "*", }, - respErr: "rpc error: code = NotFound desc = Not found", }, - // server event + // scheme event { - name: "owner: show server event by UUID", - req: &eventpb.Event_Request{ - Id: &eventpb.Event_Request_ServerId{ - ServerId: "0b1df8d7-c0cd-4a48-bcfc-248b2abe0c93", + Name: "test3_01", + Request: &eventpb.Event_Request{ + UserId: test.ConstAdminID, + Id: &eventpb.Event_Request_SchemeId{ + SchemeId: test.ConstFakeID, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - resp: &eventpb.Event_Response{ - Ip: "2001:db8:a0b:12f0::1", - Event: 8, - MetaData: []byte("{}"), + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", }, }, { - name: "owner: show server event by fake UUID", - req: &eventpb.Event_Request{ - Id: &eventpb.Event_Request_ServerId{ - ServerId: "00000000-0000-0000-0000-000000000000", + Name: "test3_02", + Request: &eventpb.Event_Request{ + UserId: test.ConstAdminID, + Id: &eventpb.Event_Request_SchemeId{ + SchemeId: test.ConstAdminSchemeEventID, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", }, - respErr: "rpc error: code = NotFound desc = Not found", - }, - { - name: "guest: show server event by UUID", - req: &eventpb.Event_Request{ - Id: &eventpb.Event_Request_ServerId{ - ServerId: "0b1df8d7-c0cd-4a48-bcfc-248b2abe0c93", - }, - UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", + Response: test.BodyTable{ + "scheme_id": test.ConstAdminEventSchemeID, + "session_id": "98e3ddfc-dab0-4d4e-b48e-ab1717acae8b", + "user_agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; LCJB; rv:11.0) like Gecko", + "ip": "192.168.1.1", + "event": float64(1), + "section": float64(1), + "meta_data": "e30=", + "created_at": "*", }, - respErr: "rpc error: code = NotFound desc = Not found", }, } - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - a := eventpb.NewEventHandlersClient(setup.grpc) - response, err := a.Event(setup.ctx, tt.req) - if err != nil { - assert.EqualError(t, err, tt.respErr) - return - } - assert.NoError(t, err) - assert.Equal(t, tt.resp.GetIp(), response.GetIp()) - assert.Equal(t, tt.resp.GetEvent(), response.GetEvent()) - assert.Equal(t, tt.resp.GetMetaData(), response.GetMetaData()) - }) - } + test.RunCaseGRPCTests(t, handler, testTable) } func Test_AddEvent(t *testing.T) { - // t.Parallel() - setup, teardownTestCase := setupTest(t) + setup, teardownTestCase := test.GRPC(t) defer teardownTestCase(t) - testCases := []struct { - name string - req *eventpb.AddEvent_Request - respErr string - }{ + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := eventpb.NewEventHandlersClient(setup) + return a.AddEvent(ctx, req.(*eventpb.AddEvent_Request)) + } + + testTable := []test.GRPCTable{ { - name: "request without parameters", - req: &eventpb.AddEvent_Request{}, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", + Name: "test0_01", + Request: &eventpb.AddEvent_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is required", + "section": "exactly one field is required in oneof", + "session_id": "value is required", + "ip": "value is required", + "event": "value is required", + }, + }, + }, + { + Name: "test0_02", + Request: &eventpb.AddEvent_Request{ + UserId: "test", + SessionId: "test", + Section: &eventpb.AddEvent_Request_Profile{ + Profile: &eventpb.Profile{ + Id: "test", + Section: eventpb.Profile_profile, + }, + }, + UserAgent: "test", + Ip: "test", + Event: eventpb.EventType_onActive, + MetaData: []byte("test"), + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value must be a valid UUID", + "session_id": "value must be a valid UUID", + "profile.id": "value must be a valid UUID", + "ip": "value must be a valid IP address", + }, + }, }, - // profile + // profile section { - name: "add profile event", - req: &eventpb.AddEvent_Request{ + Name: "test1_01", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstAdminID, + SessionId: uuid.New(), Section: &eventpb.AddEvent_Request_Profile{ Profile: &eventpb.Profile{ - Id: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + Id: test.ConstAdminID, Section: eventpb.Profile_profile, }, }, @@ -457,213 +527,176 @@ func Test_AddEvent(t *testing.T) { }, }, { - name: "add profile event with the fake profile UUID", - req: &eventpb.AddEvent_Request{ + Name: "test1_02", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstFakeID, + SessionId: uuid.New(), Section: &eventpb.AddEvent_Request_Profile{ Profile: &eventpb.Profile{ - Id: "00000000-0000-0000-0000-000000000000", + Id: test.ConstFakeID, Section: eventpb.Profile_profile, }, }, UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", Ip: "192.168.1.1", Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), + }, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", }, - respErr: "rpc error: code = Unknown desc = Failed to add", }, - { - name: "error add profile log with incorrect profile UUID", - req: &eventpb.AddEvent_Request{ + Name: "test1_03", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstFakeID, + SessionId: uuid.New(), Section: &eventpb.AddEvent_Request_Profile{ Profile: &eventpb.Profile{ - Id: "abc", + Id: "test", Section: eventpb.Profile_profile, }, }, UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", Ip: "192.168.1.1", Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "profile.id": "value must be a valid UUID", + }, }, - respErr: "rpc error: code = Unknown desc = Failed to add", }, - // project + // project section { - name: "add project event", - req: &eventpb.AddEvent_Request{ + Name: "test2_01", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstAdminID, + SessionId: uuid.New(), Section: &eventpb.AddEvent_Request_Project{ Project: &eventpb.Project{ - Id: "26060c68-5a06-4a57-b87a-be0f1e787157", - Section: eventpb.Project_project, + Id: test.ConstAdminEventProjectID, + Section: eventpb.Project_setting, }, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), }, }, { - name: "add profile event with out user UUID", - req: &eventpb.AddEvent_Request{ + Name: "test2_02", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstFakeID, + SessionId: uuid.New(), Section: &eventpb.AddEvent_Request_Project{ Project: &eventpb.Project{ - Id: "26060c68-5a06-4a57-b87a-be0f1e787157", - Section: eventpb.Project_project, + Id: test.ConstFakeID, + Section: eventpb.Project_setting, }, }, - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", + Ip: "192.168.1.1", + Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), }, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", - }, - { - name: "add profile event with the fake profile UUID", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Project{ - Project: &eventpb.Project{ - Id: "00000000-0000-0000-0000-000000000000", - Section: eventpb.Project_project, - }, - }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", }, - respErr: "rpc error: code = Unknown desc = Failed to add", }, { - name: "add profile event with the incorrect profile UUID", - req: &eventpb.AddEvent_Request{ + Name: "test2_03", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstFakeID, + SessionId: uuid.New(), Section: &eventpb.AddEvent_Request_Project{ Project: &eventpb.Project{ - Id: "abc", - Section: eventpb.Project_project, + Id: "test", + Section: eventpb.Project_setting, }, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", + Ip: "192.168.1.1", + Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), }, - respErr: "rpc error: code = Unknown desc = Failed to add", - }, - { - name: "add profile event with the fake user UUID", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Project{ - Project: &eventpb.Project{ - Id: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - Section: eventpb.Project_project, - }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "project.id": "value must be a valid UUID", }, - UserId: "00000000-0000-0000-0000-000000000000", - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), }, - respErr: "rpc error: code = Unknown desc = Failed to add", }, - // server - { - name: "add server event", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Server{ - Server: &eventpb.Server{ - Id: "0c3a8869-6fc0-4666-bf60-15475473392a", - Section: eventpb.Server_server, + // scheme section + { + Name: "test3_01", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstAdminID, + SessionId: uuid.New(), + Section: &eventpb.AddEvent_Request_Scheme{ + Scheme: &eventpb.Scheme{ + Id: test.ConstAdminEventSchemeID, + Section: eventpb.Scheme_setting, }, }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + Event: eventpb.EventType_onActive, + // MetaData: []byte("{\"test\":1}"), }, }, { - name: "add server event with out user UUID", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Server{ - Server: &eventpb.Server{ - Id: "0c3a8869-6fc0-4666-bf60-15475473392a", - Section: eventpb.Server_server, + Name: "test3_02", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstFakeID, + SessionId: uuid.New(), + Section: &eventpb.AddEvent_Request_Scheme{ + Scheme: &eventpb.Scheme{ + Id: test.ConstFakeID, + Section: eventpb.Scheme_setting, }, }, - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", + Ip: "192.168.1.1", + Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), }, - respErr: "rpc error: code = InvalidArgument desc = Invalid argument", - }, - { - name: "add server event with the fake server UUID", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Server{ - Server: &eventpb.Server{ - Id: "00000000-0000-0000-0000-000000000000", - Section: eventpb.Server_server, - }, - }, - UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Not found", }, - respErr: "rpc error: code = Unknown desc = Failed to add", }, { - name: "add profile event with the incorrect profile UUID", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Server{ - Server: &eventpb.Server{ - Id: "abc", - Section: eventpb.Server_server, + Name: "test3_03", + Request: &eventpb.AddEvent_Request{ + UserId: test.ConstFakeID, + SessionId: uuid.New(), + Section: &eventpb.AddEvent_Request_Scheme{ + Scheme: &eventpb.Scheme{ + Id: "test", + Section: eventpb.Scheme_setting, }, }, - UserId: "0c3a8869-6fc0-4666-bf60-15475473392a", - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), + UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", + Ip: "192.168.1.1", + Event: eventpb.EventType_onActive, + MetaData: []byte("{\"test\":1}"), }, - respErr: "rpc error: code = Unknown desc = Failed to add", - }, - { - name: "add profile event with the fake user id UUID", - req: &eventpb.AddEvent_Request{ - Section: &eventpb.AddEvent_Request_Server{ - Server: &eventpb.Server{ - Id: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", - Section: eventpb.Server_server, - }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "scheme.id": "value must be a valid UUID", }, - UserId: "00000000-0000-0000-0000-000000000000", - Ip: "192.168.1.1", - Event: eventpb.EventType_onCreate, - MetaData: []byte("{}"), }, - respErr: "rpc error: code = Unknown desc = Failed to add", }, } - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - a := eventpb.NewEventHandlersClient(setup.grpc) - response, err := a.AddEvent(setup.ctx, tt.req) - if err != nil { - assert.EqualError(t, err, tt.respErr) - return - } - - assert.NoError(t, err) - if _, err := uuid.Parse(response.GetRecordId()); err != nil { - assert.Error(t, err) - } - }) - } + test.RunCaseGRPCTests(t, handler, testTable) } diff --git a/internal/grpc/firewall/firewall_test.go b/internal/grpc/firewall/firewall_test.go new file mode 100644 index 00000000..4e18900c --- /dev/null +++ b/internal/grpc/firewall/firewall_test.go @@ -0,0 +1,96 @@ +package firewall_test + +import ( + "context" + "testing" + + firewallpb "github.com/werbot/werbot/internal/grpc/firewall/proto/firewall" + "github.com/werbot/werbot/internal/utils/test" + "google.golang.org/grpc/codes" +) + +func Test_IPAccess(t *testing.T) { + // t.Setenv("ENV_MODE", "test") + t.Setenv("SECURITY_GEOIP2", "../../../docker/core/GeoLite2-Country.mmdb") + + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := firewallpb.NewFirewallHandlersClient(setup) + return a.IPAccess(ctx, req.(*firewallpb.IPAccess_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &firewallpb.IPAccess_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "client_ip": "value is required", + }, + }, + }, + { // request with broken parameters + Name: "test0_02", + Request: &firewallpb.IPAccess_Request{ + ClientIp: "123", + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "client_ip": "value must be a valid IP address", + }, + }, + }, + { // request with local ip + Name: "test0_03", + Request: &firewallpb.IPAccess_Request{ + ClientIp: "127.0.0.1", + }, + Response: test.BodyTable{}, + }, + { // request with parameters + Name: "test0_04", + Request: &firewallpb.IPAccess_Request{ + ClientIp: "64.233.164.102", + }, + Response: test.BodyTable{ + "country_name": "United States", + "country_code": "US", + }, + }, + { // request with blocked ip + Name: "test0_05", + Request: &firewallpb.IPAccess_Request{ + ClientIp: "37.214.65.1", + }, + Error: test.ErrGRPC{ + Code: codes.PermissionDenied, + Message: "Access is denied for this country", + }, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +} + +func Test_UpdateFirewallListData(t *testing.T) { + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := firewallpb.NewFirewallHandlersClient(setup) + return a.UpdateFirewallListData(ctx, req.(*firewallpb.UpdateFirewallListData_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &firewallpb.UpdateFirewallListData_Request{}, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +} diff --git a/internal/grpc/license/license_test.go b/internal/grpc/license/license_test.go index 8c4f897c..9e9e961d 100644 --- a/internal/grpc/license/license_test.go +++ b/internal/grpc/license/license_test.go @@ -6,17 +6,16 @@ import ( "github.com/stretchr/testify/assert" - licensepb "github.com/werbot/werbot/internal/grpc/license/proto" + licensepb "github.com/werbot/werbot/internal/grpc/license/proto/license" "github.com/werbot/werbot/internal/utils/test" - "github.com/werbot/werbot/pkg/fsutil" + "github.com/werbot/werbot/pkg/utils/fsutil" ) func Test_license(t *testing.T) { - // t.Parallel() - ctx := context.Background() - grpc, _ := test.GRPC(ctx, t, nil, nil) - defer grpc.Close() + + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) fixturePath := "../../../fixtures/licenses/" pubKeyOk := string(fsutil.MustReadFile(fixturePath + "publicKey_ok.key")) @@ -31,8 +30,8 @@ func Test_license(t *testing.T) { resp *licensepb.License_Response respErr string }{ - { - name: "License file found", + { // License file found + name: "test0_01", licPath: licenseOk, licPubKey: pubKeyOk, req: &licensepb.License_Request{}, @@ -48,8 +47,8 @@ func Test_license(t *testing.T) { Expired: false, }, }, - { - name: "License file found and no public key", + { // License file found and no public key (gen os lic) + name: "test0_02", licPath: licenseOk, licPubKey: "", req: &licensepb.License_Request{}, @@ -65,21 +64,30 @@ func Test_license(t *testing.T) { Expired: true, }, }, - { - name: "License file not found", + { // License file not found (gen os lic) + name: "test0_03", licPath: "/license.key", licPubKey: pubKeyOk, req: &licensepb.License_Request{}, - resp: &licensepb.License_Response{}, - respErr: "rpc error: code = Unknown desc = Failed to open license file", + resp: &licensepb.License_Response{ + Customer: "Mr. Robot", + Type: "open source", + Modules: []string{"module1", "module2", "module3"}, + Limits: map[string]int32{ + "Companies": 99, + "Servers": 99, + "Users": 99, + }, + Expired: true, + }, }, - { - name: "License file found but is broken", + { // License file found but is broken + name: "test0_04", licPath: licenseErr, licPubKey: pubKeyOk, req: &licensepb.License_Request{}, resp: &licensepb.License_Response{}, - respErr: "rpc error: code = Unknown desc = The license has a broken", + respErr: "rpc error: code = PermissionDenied desc = The license has a broken", }, } @@ -88,7 +96,7 @@ func Test_license(t *testing.T) { t.Setenv("LICENSE_FILE", tt.licPath) t.Setenv("LICENSE_KEY_PUBLIC", tt.licPubKey) - l := licensepb.NewLicenseHandlersClient(grpc) + l := licensepb.NewLicenseHandlersClient(setup) response, err := l.License(ctx, tt.req) if err != nil { assert.EqualError(t, err, tt.respErr) diff --git a/internal/grpc/scheme/system_test.go b/internal/grpc/scheme/system_test.go new file mode 100644 index 00000000..fdf0a9e1 --- /dev/null +++ b/internal/grpc/scheme/system_test.go @@ -0,0 +1,299 @@ +package scheme_test + +import ( + "context" + "testing" + + schemepb "github.com/werbot/werbot/internal/grpc/scheme/proto/scheme" + "github.com/werbot/werbot/internal/utils/test" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func Test_SystemSchemesByAlias(t *testing.T) { + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := schemepb.NewSchemeHandlersClient(setup) + return a.SystemSchemesByAlias(ctx, req.(*schemepb.SystemSchemesByAlias_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &schemepb.SystemSchemesByAlias_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "alias": "value is required", + }, + }, + }, + { // request with parameters small login + Name: "test0_02", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "a", + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "alias": "value length must be at least 3 characters", + }, + }, + }, + { // request with parameters broken symbol login + Name: "test0_03", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "adm!n", + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "alias": "value does not match regex pattern `^[a-zA-Z0-9_]+$`", + }, + }, + }, + { // only broken user alias + Name: "test0_04", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "test", + }, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", + }, + }, + { // only user alias + Name: "test0_05", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "admin", + }, + Response: test.BodyTable{ + "total": float64(14), + "schemes": "*", + }, + }, + { // user and broken project alias + Name: "test0_06", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "admin_test", + }, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", + }, + }, + { // user and project alias + Name: "test0_07", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "admin_C8cXx0", + }, + Response: test.BodyTable{ + "total": float64(14), + "schemes": "*", + }, + }, + { // user, project and broken scheme alias + Name: "test0_08", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "admin_C8cXx0_test", + }, + Error: test.ErrGRPC{ + Code: codes.NotFound, + Message: "Scheme not found", + }, + }, + { // user, project and scheme alias + Name: "test0_09", + Request: &schemepb.SystemSchemesByAlias_Request{ + Alias: "admin_C8cXx0_7TrR6t", + }, + Response: test.BodyTable{ + "total": float64(1), + "schemes.0.project_id": "d958ee44-a960-420e-9bbf-c7a35084c4aa", + "schemes.0.scheme_id": "2acb611c-4ab9-4540-954a-ddcfd81ee308", + "schemes.0.scheme_type": float64(205), + "schemes.0.auth_method": float64(1), + "schemes.0.alias": "admin_C8cXx0_7TrR6t", + "schemes.0.title": "Elastic server #1", + }, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +} + +func Test_SystemSchemeAccess(t *testing.T) { + t.Setenv("SECURITY_GEOIP2", "../../../docker/core/GeoLite2-Country.mmdb") + + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := schemepb.NewSchemeHandlersClient(setup) + return a.SystemSchemeAccess(ctx, req.(*schemepb.SystemSchemeAccess_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &schemepb.SystemSchemeAccess_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "scheme_id": "value is required", + "client_ip": "value is required", + }, + }, + }, + { // request with broken parameters + Name: "test0_02", + Request: &schemepb.SystemSchemeAccess_Request{ + SchemeId: "123", + ClientIp: "321", + }, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "scheme_id": "value must be a valid UUID", + "client_ip": "value must be a valid IP address", + }, + }, + }, + { // request with global blocked ip + Name: "test0_03", + Request: &schemepb.SystemSchemeAccess_Request{ + SchemeId: test.ConstAdminSchemeSSH1ID, + ClientIp: "178.239.2.11", + }, + Error: test.ErrGRPC{ + Code: codes.PermissionDenied, + Message: "Access is denied for this ip", + }, + }, + { // request with global blocked country + Name: "test0_04", + Request: &schemepb.SystemSchemeAccess_Request{ + SchemeId: test.ConstAdminSchemeSSH1ID, + ClientIp: "86.57.251.89", + }, + Error: test.ErrGRPC{ + Code: codes.PermissionDenied, + Message: "Access is denied for this country", + }, + }, + { // request with blocked time + Name: "test0_05", + Request: &schemepb.SystemSchemeAccess_Request{ + SchemeId: test.ConstAdminSchemeSSH1ID, + ClientIp: "64.233.162.100", + Timestamp: ×tamppb.Timestamp{ // 2024-09-16 00:18:09.455761+00 + Seconds: 1726445889, + Nanos: 455761000, + }, + }, + Error: test.ErrGRPC{ + Code: codes.PermissionDenied, + Message: "Access is denied for this time", + }, + }, + { // request + // Debug: true, + Name: "test0_06", + Request: &schemepb.SystemSchemeAccess_Request{ + SchemeId: test.ConstAdminSchemeSSH1ID, + ClientIp: "64.233.162.100", + Timestamp: ×tamppb.Timestamp{ // 2024-09-16 01:18:09.455761+00 + Seconds: 1726449489, + Nanos: 455761000, + }, + }, + Response: test.BodyTable{ + "project_id": test.ConstAdminProject1ID, + "scheme_type": float64(103), + "access.server_ssh.alias": "onxzU5", + "access.server_ssh.password.password": "***", + }, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +} + +func Test_SystemHostKey(t *testing.T) { + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := schemepb.NewSchemeHandlersClient(setup) + return a.SystemHostKey(ctx, req.(*schemepb.SystemHostKey_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &schemepb.SystemHostKey_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "scheme_id": "value is required", + }, + }, + }, + { // request + Name: "test0_02", + Request: &schemepb.SystemHostKey_Request{ + SchemeId: test.ConstAdminSchemeSSH1ID, + }, + Response: test.BodyTable{ + "hostkey": "dGVzdAo=", + }, + }, + { // request + Name: "test0_03", + Request: &schemepb.SystemHostKey_Request{ + SchemeId: test.ConstAdminSchemeSSH2ID, + }, + Response: test.BodyTable{ + "hostkey": nil, + }, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +} + +func Test_SystemUpdateHostKey(t *testing.T) { + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := schemepb.NewSchemeHandlersClient(setup) + return a.SystemUpdateHostKey(ctx, req.(*schemepb.SystemUpdateHostKey_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &schemepb.SystemUpdateHostKey_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "scheme_id": "value is required", + "hostkey": "value is required", + }, + }, + }, + { // request + Name: "test0_02", + Request: &schemepb.SystemUpdateHostKey_Request{ + SchemeId: test.ConstAdminSchemeSSH1ID, + Hostkey: []byte("message"), + }, + Response: test.BodyTable{}, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +} diff --git a/internal/grpc/scheme/user_test.go b/internal/grpc/scheme/user_test.go new file mode 100644 index 00000000..4ffaabf6 --- /dev/null +++ b/internal/grpc/scheme/user_test.go @@ -0,0 +1,99 @@ +package scheme_test + +import ( + "context" + "testing" + + schemeaccesspb "github.com/werbot/werbot/internal/grpc/scheme/proto/access" + schemepb "github.com/werbot/werbot/internal/grpc/scheme/proto/scheme" + "github.com/werbot/werbot/internal/utils/test" + "google.golang.org/grpc/codes" +) + +func Test_UserSchemes(t *testing.T) { + setup, teardownTestCase := test.GRPC(t) + defer teardownTestCase(t) + + handler := func(ctx context.Context, req test.ProtoMessage) (test.ProtoMessage, error) { + a := schemepb.NewSchemeHandlersClient(setup) + return a.UserSchemes(ctx, req.(*schemepb.UserSchemes_Request)) + } + + testTable := []test.GRPCTable{ + { // request without parameters + Name: "test0_01", + Request: &schemepb.UserSchemes_Request{}, + Error: test.ErrGRPC{ + Code: codes.InvalidArgument, + Message: map[string]any{ + "user_id": "value is empty, which is not a valid UUID", + }, + }, + }, + { // user schemes + Name: "test0_02", + Request: &schemepb.UserSchemes_Request{ + UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", + }, + Response: test.BodyTable{ + "total.100": float64(5), + "total.200": float64(10), + "total.300": float64(2), + "total.400": float64(3), + "total.500": float64(8), + "total.600": float64(2), + "schemes.0.project_id": "2bef1080-cd6e-49e5-8042-1224cf6a3da9", + }, + }, + { // user database schemes + // Debug: true, + Name: "test0_03", + Request: &schemepb.UserSchemes_Request{ + UserId: "c180ad5c-0c65-4cee-8725-12931cb5abb3", + SchemeType: schemeaccesspb.SchemeType_database, + }, + Response: test.BodyTable{ + "total.100": float64(5), + "total.200": float64(10), + "total.300": float64(2), + "total.400": float64(3), + "total.500": float64(8), + "total.600": float64(2), + "schemes.0.project_id": "2bef1080-cd6e-49e5-8042-1224cf6a3da9", + }, + }, + + { // admin schemes + // Debug: true, + Name: "test0_04", + Request: &schemepb.UserSchemes_Request{ + UserId: "008feb1d-12f2-4bc3-97ff-c8d7fb9f7686", + }, + Response: test.BodyTable{ + "total.100": float64(5), + "total.200": float64(7), + "total.300": float64(2), + "total.400": float64(2), + "total.500": float64(0), + "total.600": float64(0), + }, + }, + + { // user1 schemes + Name: "test0_05", + Request: &schemepb.UserSchemes_Request{ + UserId: "b3dc36e2-7f84-414b-b147-7ac850369518", + }, + Response: test.BodyTable{ + "total.100": float64(1), + "total.200": float64(0), + "total.300": float64(0), + "total.400": float64(0), + "total.500": float64(0), + "total.600": float64(0), + }, + }, + } + + test.RunCaseGRPCTests(t, handler, testTable) +}