mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-07-04 17:06:49 +00:00
Add backend unit tests
This commit is contained in:
@ -1,46 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/qri-io/jsonschema"
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidJSON is an error for invalid json
|
||||
ErrInvalidJSON = eris.New("JSON is invalid")
|
||||
// ErrInvalidPayload is an error for invalid incoming data
|
||||
ErrInvalidPayload = eris.New("Payload is invalid")
|
||||
)
|
||||
|
||||
// ValidateRequestSchema takes a Schema and the Content to validate against it
|
||||
func ValidateRequestSchema(schema string, requestBody []byte) ([]jsonschema.KeyError, error) {
|
||||
var jsonErrors []jsonschema.KeyError
|
||||
var schemaBytes = []byte(schema)
|
||||
|
||||
// Make sure the body is valid JSON
|
||||
if !isJSON(requestBody) {
|
||||
return jsonErrors, ErrInvalidJSON
|
||||
}
|
||||
|
||||
rs := &jsonschema.Schema{}
|
||||
if err := json.Unmarshal(schemaBytes, rs); err != nil {
|
||||
return jsonErrors, err
|
||||
}
|
||||
|
||||
var validationErr error
|
||||
ctx := context.TODO()
|
||||
if jsonErrors, validationErr = rs.ValidateBytes(ctx, requestBody); len(jsonErrors) > 0 {
|
||||
return jsonErrors, validationErr
|
||||
}
|
||||
|
||||
// Valid
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func isJSON(bytes []byte) bool {
|
||||
var js map[string]interface{}
|
||||
return json.Unmarshal(bytes, &js) == nil
|
||||
}
|
@ -11,6 +11,12 @@ import (
|
||||
"npm/internal/logger"
|
||||
|
||||
"github.com/qri-io/jsonschema"
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidPayload is an error for invalid incoming data
|
||||
ErrInvalidPayload = eris.New("Payload is invalid")
|
||||
)
|
||||
|
||||
// Response interface for standard API results
|
||||
|
180
backend/internal/api/http/responses_test.go
Normal file
180
backend/internal/api/http/responses_test.go
Normal file
@ -0,0 +1,180 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"npm/internal/entity/user"
|
||||
"npm/internal/model"
|
||||
"testing"
|
||||
|
||||
"github.com/qri-io/jsonschema"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestResultResponseJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status int
|
||||
given interface{}
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "simple response",
|
||||
status: http.StatusOK,
|
||||
given: true,
|
||||
want: "{\"result\":true}",
|
||||
},
|
||||
{
|
||||
name: "detailed response",
|
||||
status: http.StatusBadRequest,
|
||||
given: user.Model{
|
||||
ModelBase: model.ModelBase{ID: 10},
|
||||
Email: "me@example.com",
|
||||
Name: "John Doe",
|
||||
Nickname: "Jonny",
|
||||
},
|
||||
want: "{\"result\":{\"id\":10,\"created_at\":0,\"updated_at\":0,\"name\":\"John Doe\",\"nickname\":\"Jonny\",\"email\":\"me@example.com\",\"is_disabled\":false,\"gravatar_url\":\"\"}}",
|
||||
},
|
||||
{
|
||||
name: "error response",
|
||||
status: http.StatusNotFound,
|
||||
given: ErrorResponse{
|
||||
Code: 404,
|
||||
Message: "Not found",
|
||||
Invalid: []string{"your", "page", "was", "not", "found"},
|
||||
},
|
||||
want: "{\"result\":null,\"error\":{\"code\":404,\"message\":\"Not found\",\"invalid\":[\"your\",\"page\",\"was\",\"not\",\"found\"]}}",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/anything", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ResultResponseJSON(w, r, tt.status, tt.given)
|
||||
res := w.Result()
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to be nil got %v", err)
|
||||
}
|
||||
assert.Equal(t, tt.want, string(body))
|
||||
assert.Equal(t, tt.status, res.StatusCode)
|
||||
assert.Equal(t, "application/json; charset=utf-8", res.Header.Get("Content-Type"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResultSchemaErrorJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
given []jsonschema.KeyError
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "case a",
|
||||
given: []jsonschema.KeyError{
|
||||
{
|
||||
PropertyPath: "/something",
|
||||
InvalidValue: "name",
|
||||
Message: "Name cannot be empty",
|
||||
},
|
||||
},
|
||||
want: "{\"result\":null,\"error\":{\"code\":400,\"message\":{},\"invalid\":[{\"propertyPath\":\"/something\",\"invalidValue\":\"name\",\"message\":\"Name cannot be empty\"}]}}",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/anything", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ResultSchemaErrorJSON(w, r, tt.given)
|
||||
res := w.Result()
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to be nil got %v", err)
|
||||
}
|
||||
assert.Equal(t, tt.want, string(body))
|
||||
assert.Equal(t, 400, res.StatusCode)
|
||||
assert.Equal(t, "application/json; charset=utf-8", res.Header.Get("Content-Type"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResultErrorJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status int
|
||||
message string
|
||||
extended interface{}
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "case a",
|
||||
status: http.StatusBadGateway,
|
||||
message: "Oh not something is not acceptable",
|
||||
extended: nil,
|
||||
want: "{\"result\":null,\"error\":{\"code\":502,\"message\":\"Oh not something is not acceptable\"}}",
|
||||
},
|
||||
{
|
||||
name: "case b",
|
||||
status: http.StatusNotAcceptable,
|
||||
message: "Oh not something is not acceptable again",
|
||||
extended: []string{"name is not allowed", "dob is wrong or something"},
|
||||
want: "{\"result\":null,\"error\":{\"code\":406,\"message\":\"Oh not something is not acceptable again\",\"invalid\":[\"name is not allowed\",\"dob is wrong or something\"]}}",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/anything", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ResultErrorJSON(w, r, tt.status, tt.message, tt.extended)
|
||||
res := w.Result()
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to be nil got %v", err)
|
||||
}
|
||||
assert.Equal(t, tt.want, string(body))
|
||||
assert.Equal(t, tt.status, res.StatusCode)
|
||||
assert.Equal(t, "application/json; charset=utf-8", res.Header.Get("Content-Type"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotFound(t *testing.T) {
|
||||
t.Run("basic test", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/anything", nil)
|
||||
w := httptest.NewRecorder()
|
||||
NotFound(w, r)
|
||||
res := w.Result()
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to be nil got %v", err)
|
||||
}
|
||||
assert.Equal(t, "{\"result\":null,\"error\":{\"code\":404,\"message\":\"Not found\"}}", string(body))
|
||||
assert.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
assert.Equal(t, "application/json; charset=utf-8", res.Header.Get("Content-Type"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestResultResponseText(t *testing.T) {
|
||||
t.Run("basic test", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/anything", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ResultResponseText(w, r, http.StatusOK, "omg this works")
|
||||
res := w.Result()
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to be nil got %v", err)
|
||||
}
|
||||
assert.Equal(t, "omg this works", string(body))
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode)
|
||||
assert.Equal(t, "text/plain; charset=utf-8", res.Header.Get("Content-Type"))
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user