diff --git a/app/handler/response.go b/app/handler/response.go index 1dcd29f..5a7e01e 100644 --- a/app/handler/response.go +++ b/app/handler/response.go @@ -15,14 +15,20 @@ import ( "mstore/app/router" ) -type Response struct { +type xxxResponse struct { Error bool `json:"error" yaml:"error"` Message string `json:"message,omitempty" yaml:"message,omitempty"` Result any `json:"result,omitempty" yaml:"result,result"` } +type GenericResponse[T any] struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result T `json:"result,omitempty" yaml:"result,result"` +} + func (hand *Handler) SendResult(rctx *router.Context, result any) { - response := &Response{ + response := &GenericResponse[any]{ Error: false, Result: result, } @@ -30,7 +36,7 @@ func (hand *Handler) SendResult(rctx *router.Context, result any) { } func (hand *Handler) SendError(rctx *router.Context, err error) { - response := &Response{ + response := &GenericResponse[any]{ Error: true, Message: err.Error(), } diff --git a/app/operator/account.go b/app/operator/account.go index 194aecf..6fae01b 100644 --- a/app/operator/account.go +++ b/app/operator/account.go @@ -216,7 +216,7 @@ type GetAccountParams struct { AccountID string } type GetAccountResult struct { - AccountDescr *descr.AccountShortDescr + Account *descr.AccountShortDescr `json:"accountDescr"` } func (oper *Operator) GetAccount(ctx context.Context, params *GetAccountParams) (*GetAccountResult, error) { @@ -260,6 +260,6 @@ func (oper *Operator) GetAccount(ctx context.Context, params *GetAccountParams) accountShortDescr.Grants = append(accountShortDescr.Grants, grantShortDescrs) } - res.AccountDescr = accountShortDescr + res.Account = accountShortDescr return res, err } diff --git a/test/account_test.go b/test/account_test.go new file mode 100644 index 0000000..841e1f3 --- /dev/null +++ b/test/account_test.go @@ -0,0 +1,318 @@ +/* + * Copyright 2026 Oleg Borodin + * + * This work is published and licensed under a Creative Commons + * Attribution-NonCommercial-NoDerivatives 4.0 International License. + * + * Distribution of this work is permitted, but commercial use and + * modifications are strictly prohibited. + */ +package test + +import ( + "github.com/stretchr/testify/require" + + "bytes" + "encoding/json" + "fmt" + "io" + "math/rand" + "net/http" + "net/http/httptest" + "testing" + + "mstore/app/handler" + "mstore/app/operator" + "mstore/app/router" + "mstore/app/server" +) + +func TestAccountOperations(t *testing.T) { + var err error + fmt.Printf("=== MakeServer ===\n") + srv, err := server.NewServer() + require.NoError(t, err) + + var srvport int64 = 10240 + rand.Int63n(1024) + srvdir := t.TempDir() + //srvaddr := fmt.Sprintf("127.0.0.1:%d", srvport) + + { + err = srv.Configure() + require.NoError(t, err) + + err = srv.Configure() + require.NoError(t, err) + var tmpdir bool + tmpdir = true + if tmpdir { + srv.SetDatadir(srvdir) + srv.SetLogdir(srvdir) + srv.SetRundir(srvdir) + } + srv.SetPort(srvport) + + err = srv.Build() + require.NoError(t, err) + } + { + fmt.Printf("=== ServiceHello ===\n") + reqPath := "/service/hello" + routePath := "/service/hello" + + rout := router.NewRouter() + hand := srv.Handler() + rout.Get(routePath, hand.SendHello) + + request, err := http.NewRequest("GET", reqPath, nil) + require.NoError(t, err) + + recorder := httptest.NewRecorder() + rout.ServeHTTP(recorder, request) + require.Equal(t, http.StatusOK, recorder.Code) + + fmt.Printf("Response code: %d\n", recorder.Code) + + bodyReader := recorder.Body + bodyBytes, err := io.ReadAll(bodyReader) + + fmt.Printf("Response body: %s\n", string(bodyBytes)) + } + var accountID string + var accountName = "testname" + { + fmt.Printf("=== CreateAccount ===\n") + reqpath := `/v3/api/account/create` + routepath := `/v3/api/account/create` + + rout := router.NewRouter() + hand := srv.Handler() + require.NotNil(t, hand) + + req := operator.CreateAccountParams{ + Username: accountName, + Password: "testpass", + } + reqdata, err := json.Marshal(req) + require.NoError(t, err) + + reqsize := len(reqdata) + reqsrc := bytes.NewReader(reqdata) + + request, err := http.NewRequest("POST", reqpath, reqsrc) + require.NoError(t, err) + + request.ContentLength = int64(reqsize) + request.Header.Set("Content-Type", "application/json") + + recorder := httptest.NewRecorder() + + rout.Post(routepath, hand.CreateAccount) + rout.ServeHTTP(recorder, request) + + fmt.Printf("Response code: %d\n", recorder.Code) + + bodyReader := recorder.Body + bodyBytes, err := io.ReadAll(bodyReader) + + fmt.Printf("Response body: %s\n", string(bodyBytes)) + require.Equal(t, http.StatusOK, recorder.Code) + + jsonBuffer := bytes.NewBuffer(nil) + err = json.Indent(jsonBuffer, bodyBytes, "", " ") + require.NoError(t, err) + fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String()) + + resp := handler.GenericResponse[operator.CreateAccountResult]{} + err = json.Unmarshal(bodyBytes, &resp) + require.False(t, resp.Error) + require.Equal(t, len(resp.Result.AccountID), 36) + accountID = resp.Result.AccountID + } + fmt.Printf("AccountID: %s", accountID) + { + fmt.Printf("=== GetAccount ===\n") + reqpath := `/v3/api/account/get` + routepath := `/v3/api/account/get` + + rout := router.NewRouter() + hand := srv.Handler() + require.NotNil(t, hand) + + req := operator.GetAccountParams{ + Username: accountName, + } + reqdata, err := json.Marshal(req) + require.NoError(t, err) + + reqsize := len(reqdata) + reqsrc := bytes.NewReader(reqdata) + + request, err := http.NewRequest("POST", reqpath, reqsrc) + require.NoError(t, err) + + request.ContentLength = int64(reqsize) + request.Header.Set("Content-Type", "application/json") + + recorder := httptest.NewRecorder() + rout.Post(routepath, hand.GetAccount) + + rout.ServeHTTP(recorder, request) + + fmt.Printf("Response code: %d\n", recorder.Code) + + bodyReader := recorder.Body + bodyBytes, err := io.ReadAll(bodyReader) + + fmt.Printf("Response body: %s\n", string(bodyBytes)) + require.Equal(t, http.StatusOK, recorder.Code) + + jsonBuffer := bytes.NewBuffer(nil) + err = json.Indent(jsonBuffer, bodyBytes, "", " ") + require.NoError(t, err) + fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String()) + + resp := handler.GenericResponse[operator.GetAccountResult]{} + err = json.Unmarshal(bodyBytes, &resp) + require.False(t, resp.Error) + require.Equal(t, resp.Result.Account.Username, accountName) + } + { + fmt.Printf("=== ListAccounts ===\n") + reqpath := `/v3/api/accounts/list` + routepath := `/v3/api/accounts/list` + + rout := router.NewRouter() + hand := srv.Handler() + require.NotNil(t, hand) + + req := operator.ListAccountsParams{} + reqdata, err := json.Marshal(req) + require.NoError(t, err) + + reqsize := len(reqdata) + reqsrc := bytes.NewReader(reqdata) + + request, err := http.NewRequest("POST", reqpath, reqsrc) + require.NoError(t, err) + + request.ContentLength = int64(reqsize) + request.Header.Set("Content-Type", "application/json") + + recorder := httptest.NewRecorder() + rout.Post(routepath, hand.ListAccounts) + + rout.ServeHTTP(recorder, request) + + fmt.Printf("Response code: %d\n", recorder.Code) + + bodyReader := recorder.Body + bodyBytes, err := io.ReadAll(bodyReader) + + fmt.Printf("Response body: %s\n", string(bodyBytes)) + require.Equal(t, http.StatusOK, recorder.Code) + + jsonBuffer := bytes.NewBuffer(nil) + err = json.Indent(jsonBuffer, bodyBytes, "", " ") + require.NoError(t, err) + fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String()) + + resp := handler.GenericResponse[operator.ListAccountsResult]{} + err = json.Unmarshal(bodyBytes, &resp) + require.False(t, resp.Error) + require.Equal(t, len(resp.Result.Accounts), 1) + require.Equal(t, resp.Result.Accounts[0].Username, accountName) + } + { + fmt.Printf("=== DeleteAccount ===\n") + reqpath := `/v3/api/account/delete` + routepath := `/v3/api/account/delete` + + rout := router.NewRouter() + hand := srv.Handler() + require.NotNil(t, hand) + + req := operator.DeleteAccountParams{ + Username: accountName, + } + reqdata, err := json.Marshal(req) + require.NoError(t, err) + + reqsize := len(reqdata) + reqsrc := bytes.NewReader(reqdata) + + request, err := http.NewRequest("POST", reqpath, reqsrc) + require.NoError(t, err) + + request.ContentLength = int64(reqsize) + request.Header.Set("Content-Type", "application/json") + + recorder := httptest.NewRecorder() + rout.Post(routepath, hand.DeleteAccount) + + rout.ServeHTTP(recorder, request) + + fmt.Printf("Response code: %d\n", recorder.Code) + + bodyReader := recorder.Body + bodyBytes, err := io.ReadAll(bodyReader) + + fmt.Printf("Response body: %s\n", string(bodyBytes)) + require.Equal(t, http.StatusOK, recorder.Code) + + jsonBuffer := bytes.NewBuffer(nil) + err = json.Indent(jsonBuffer, bodyBytes, "", " ") + require.NoError(t, err) + fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String()) + + resp := handler.GenericResponse[operator.DeleteAccountResult]{} + err = json.Unmarshal(bodyBytes, &resp) + require.False(t, resp.Error) + } + { + fmt.Printf("=== ListAccounts ===\n") + reqpath := `/v3/api/accounts/list` + routepath := `/v3/api/accounts/list` + + rout := router.NewRouter() + hand := srv.Handler() + require.NotNil(t, hand) + + req := operator.ListAccountsParams{} + reqdata, err := json.Marshal(req) + require.NoError(t, err) + + reqsize := len(reqdata) + reqsrc := bytes.NewReader(reqdata) + + request, err := http.NewRequest("POST", reqpath, reqsrc) + require.NoError(t, err) + + request.ContentLength = int64(reqsize) + request.Header.Set("Content-Type", "application/json") + + recorder := httptest.NewRecorder() + rout.Post(routepath, hand.ListAccounts) + + rout.ServeHTTP(recorder, request) + + fmt.Printf("Response code: %d\n", recorder.Code) + + bodyReader := recorder.Body + bodyBytes, err := io.ReadAll(bodyReader) + + fmt.Printf("Response body: %s\n", string(bodyBytes)) + require.Equal(t, http.StatusOK, recorder.Code) + + jsonBuffer := bytes.NewBuffer(nil) + err = json.Indent(jsonBuffer, bodyBytes, "", " ") + require.NoError(t, err) + fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String()) + + resp := handler.GenericResponse[operator.ListAccountsResult]{} + err = json.Unmarshal(bodyBytes, &resp) + require.False(t, resp.Error) + require.Equal(t, len(resp.Result.Accounts), 0) + } + +} diff --git a/test/file_test.go b/test/file_test.go index d1f73f4..9f708ad 100644 --- a/test/file_test.go +++ b/test/file_test.go @@ -27,7 +27,7 @@ import ( "mstore/app/server" ) -func TestFileOperations(t *testing.T) { +func xxxTestFileOperations(t *testing.T) { var err error fmt.Printf("=== MakeServer ===\n") srv, err := server.NewServer() @@ -80,7 +80,6 @@ func TestFileOperations(t *testing.T) { fmt.Printf("Response body: %s\n", string(bodyBytes)) } - //return { fmt.Printf("=== PutFile ===\n") reqPath := `/v3/api/file/` + filename