From 78671549c3c7e15e06f44861db35f23c2efe11ea Mon Sep 17 00:00:00 2001 From: grumbulon Date: Mon, 30 Jan 2023 23:23:35 -0500 Subject: [PATCH] I <3 TESTS --- internal/api/api.go | 2 +- internal/api/api_test.go | 181 ++++++++++++++++++++++++++++++++++++- internal/api/testhelper.go | 5 + internal/api/zone.go | 9 +- 4 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 internal/api/testhelper.go diff --git a/internal/api/api.go b/internal/api/api.go index b8f3f73..6e92894 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -109,7 +109,7 @@ func API() http.Handler { api.Use(jwtauth.Authenticator) api.With(setDBMiddleware).Post("/upload", ReceiveFile) - api.With(setDBMiddleware).Post("/parse", ZoneFiles) + api.With(setDBMiddleware).Post("/parse", ParseZoneFiles) }) // Open routes diff --git a/internal/api/api_test.go b/internal/api/api_test.go index 44aafcb..970f4c8 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -1,11 +1,16 @@ package api import ( + "bytes" "encoding/json" + "fmt" "io" + "mime/multipart" "net/http" "net/http/httptest" "net/url" + "os" + "path/filepath" "strings" "testing" "time" @@ -13,6 +18,7 @@ import ( "git.freecumextremist.com/grumbulon/pomme/internal" "git.freecumextremist.com/grumbulon/pomme/internal/db" "github.com/go-chi/chi/v5" + "github.com/go-chi/jwtauth/v5" "github.com/stretchr/testify/assert" "golang.org/x/crypto/bcrypt" ) @@ -26,9 +32,22 @@ type response struct { type accountTest struct { username string password string + token string url string } +func makeTestToken(username string) (tokenString string, err error) { + claim := map[string]interface{}{"username": username, "admin": false} + + jwtauth.SetExpiry(claim, time.Now().Add(time.Hour)) + + if _, tokenString, err = tokenAuth.Encode(claim); err == nil { + return + } + + return "", fmt.Errorf("unable to generate JWT: %w", err) +} + func TestAPI(t *testing.T) { config, err := internal.ReadConfig() if err != nil { @@ -63,7 +82,7 @@ func TestAPI(t *testing.T) { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(tester.password), bcrypt.DefaultCost) if err != nil { - return + assert.NotNil(t, err) } db.Create(&internal.User{Username: tester.username, HashedPassword: string(hashedPassword)}) @@ -71,14 +90,25 @@ func TestAPI(t *testing.T) { tester.TestMakeAccount(t) tester.TestLogin(t) tester.TestLogout(t) + tester.TestUpload(t) } func Init(url string) accountTest { - return accountTest{ - username: autoUname(), + user := autoUname() + + token, err := makeTestToken(user) + if err != nil { + return accountTest{} + } + + test := accountTest{ + username: user, password: "merde", url: url, + token: token, } + + return test } func (a *accountTest) TestMakeAccount(t *testing.T) { @@ -172,3 +202,148 @@ func (a *accountTest) TestLogout(t *testing.T) { assert.Equal(t, http.StatusOK, target.Status) } } + +type expectedValues struct { + response int +} + +func (a *accountTest) TestUpload(t *testing.T) { + testCases := []struct { + name string + file string + contentType string + fileContents []byte + expected expectedValues + }{ + { + name: "Should fail to upload an empty file", + file: "badzonefile", + contentType: "audio/aac", + expected: expectedValues{ + response: http.StatusInternalServerError, + }, + }, + { + name: "Should upload a valid file", + file: "zonefile", + contentType: "multipart/form-data", + fileContents: []byte{}, + expected: expectedValues{ + response: http.StatusCreated, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var ( + f *os.File + target response + err error + buf = new(bytes.Buffer) + w = multipart.NewWriter(buf) + ) + + switch tc.name { + case "Should fail to upload an empty file": + f, err = os.CreateTemp(".", tc.file) + if err != nil { + assert.NotNil(t, err) + } + default: + f, err = os.CreateTemp(".", "zonefile") + if err != nil { + assert.NotNil(t, err) + } + + if err = os.WriteFile(f.Name(), zonebytes, 0o600); err != nil { + assert.NotNil(t, err) + } + } + + defer os.Remove(f.Name()) //nolint: errcheck + + client := http.Client{} + + part, err := w.CreateFormFile("file", filepath.Base(f.Name())) + if err != nil { + assert.NotNil(t, err) + } + + b, err := os.ReadFile(f.Name()) + if err != nil { + assert.NotNil(t, err) + } + + _, err = part.Write(b) + if err != nil { + assert.NotNil(t, err) + } + + err = w.Close() + if err != nil { + assert.NotNil(t, err) + } + + if req, err := http.NewRequest(http.MethodPost, a.url+`/api/upload`, buf); err == nil { + switch tc.name { + case "Should fail to upload an empty file": + req.Header.Add("Content-Type", tc.contentType) + default: + req.Header.Add("Content-Type", w.FormDataContentType()) + } + + req.Header.Add("Authorization", `Bearer:`+a.token) + req.Header.Add("User-Agent", "pomme-api-test-slave") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + assert.Equal(t, tc.expected.response, target.Status) + } + + if tc.name == "Should upload a valid file" { + parse(t, f.Name(), a) + } + }) + } +} + +func parse(t *testing.T, fname string, a *accountTest) { + var target response + + client := http.Client{} + + form := url.Values{} + + form.Add("filename", filepath.Clean(fname)) + + if req, err := http.NewRequest(http.MethodPost, a.url+`/api/parse`, strings.NewReader(form.Encode())); err == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Authorization", `Bearer:`+a.token) + req.Header.Add("User-Agent", "pomme-api-test-slave") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + assert.Equal(t, http.StatusOK, target.Status) + } +} diff --git a/internal/api/testhelper.go b/internal/api/testhelper.go new file mode 100644 index 0000000..858f3a8 --- /dev/null +++ b/internal/api/testhelper.go @@ -0,0 +1,5 @@ +package api + +// you have made a gave mistake opening this file + +var zonebytes []uint8 = []uint8([]byte{0x24, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x53, 0x4f, 0x41, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x31, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x20, 0x28, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7a, 0x6f, 0x6e, 0x65, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x79, 0x6e, 0x64, 0x6e, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x31, 0x36, 0x30, 0x37, 0x32, 0x37, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x72, 0x65, 0x74, 0x72, 0x79, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x34, 0x38, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x38, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x3b, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x74, 0x74, 0x6c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x31, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x32, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x33, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x34, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x4d, 0x58, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x4d, 0x58, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x20, 0x76, 0x70, 0x6e, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x4d, 0x58, 0x20, 0x20, 0x20, 0x20, 0x33, 0x30, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x34, 0x2e, 0x31, 0x33, 0x2e, 0x32, 0x34, 0x38, 0x2e, 0x31, 0x30, 0x36, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x54, 0x58, 0x54, 0x20, 0x20, 0x20, 0x22, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x70, 0x66, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x7e, 0x61, 0x6c, 0x6c, 0x22, 0xa, 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x34, 0x30, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x34, 0x2e, 0x31, 0x33, 0x2e, 0x32, 0x34, 0x38, 0x2e, 0x31, 0x30, 0x36, 0xa, 0x76, 0x70, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x31, 0x36, 0x2e, 0x31, 0x34, 0x36, 0x2e, 0x34, 0x35, 0x2e, 0x32, 0x34, 0x30, 0xa, 0x77, 0x65, 0x62, 0x61, 0x70, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x31, 0x36, 0x2e, 0x31, 0x34, 0x36, 0x2e, 0x34, 0x36, 0x2e, 0x31, 0x30, 0xa, 0x77, 0x65, 0x62, 0x61, 0x70, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x31, 0x36, 0x2e, 0x31, 0x34, 0x36, 0x2e, 0x34, 0x36, 0x2e, 0x31, 0x31, 0xa, 0x77, 0x77, 0x77, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x33, 0x32, 0x30, 0x30, 0x20, 0x43, 0x4e, 0x41, 0x4d, 0x45, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa}) diff --git a/internal/api/zone.go b/internal/api/zone.go index dee1f8a..f028623 100644 --- a/internal/api/zone.go +++ b/internal/api/zone.go @@ -13,6 +13,7 @@ import ( "git.freecumextremist.com/grumbulon/pomme/internal" "git.freecumextremist.com/grumbulon/pomme/internal/util" "github.com/go-chi/jwtauth/v5" + "github.com/go-chi/render" "github.com/miekg/dns" "gorm.io/gorm" ) @@ -140,7 +141,7 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) { // @Security Bearer // // @Router /api/parse [post] -func ZoneFiles(w http.ResponseWriter, r *http.Request) { +func ParseZoneFiles(w http.ResponseWriter, r *http.Request) { var result internal.ZoneRequest _, claims, _ := jwtauth.FromContext(r.Context()) @@ -187,6 +188,12 @@ func ZoneFiles(w http.ResponseWriter, r *http.Request) { return } + + resp := internal.Response{ + Message: "Successfully parsed zonefile", + HTTPResponse: http.StatusOK, + } + render.JSON(w, r, resp) } func newZoneRequest(filename string, user string) *ZoneRequest {