satellite/admin: Send JSON content-type for errors

Fix the Admin API endpoints when it response with a client error
response code.

The most of the client response error send a JSON body but the
`Content-Type` header wasn't set to the appropriated value. This commit
fixes them and it adds assertions to the tests to very the
`Content-Type` header.

Updates the README to briefly document about the format of the client
errors endpoints responses.

Change-Id: Ifaf2122def801701211438ce241046be1adc0e8c
This commit is contained in:
Ivan Fraixedes 2021-10-01 13:36:41 +02:00
parent 821a077f7c
commit bb575ef739
No known key found for this signature in database
GPG Key ID: 042B474597F96DB7
8 changed files with 164 additions and 84 deletions

View File

@ -7,38 +7,60 @@ Requires setting `Authorization` header for requests.
<!-- Auto-generate this ToC with https://github.com/ycd/toc -->
<!-- toc -->
- [satellite/admin](#satelliteadmin)
* [User Management](#user-management)
* [POST /api/users](#post-apiusers)
* [PUT /api/users/{user-email}](#put-apiusersuser-email)
* [GET /api/users/{user-email}](#get-apiusersuser-email)
* [DELETE /api/users/{user-email}](#delete-apiusersuser-email)
* [Coupon Management](#coupon-management)
* [POST /api/coupons](#post-apicoupons)
* [GET /api/coupons/{coupon-id}](#get-apicouponscoupon-id)
* [DELETE /api/coupons/{coupon-id}](#delete-apicouponscoupon-id)
* [Project Management](#project-management)
* [POST /api/projects](#post-apiprojects)
* [GET /api/projects/{project-id}](#get-apiprojectsproject-id)
* [PUT /api/projects/{project-id}](#put-apiprojectsproject-id)
* [DELETE /api/projects/{project-id}](#delete-apiprojectsproject-id)
* [GET /api/projects/{project}/apikeys](#get-apiprojectsprojectapikeys)
* [POST /api/projects/{project}/apikeys](#post-apiprojectsprojectapikeys)
* [DELETE /api/projects/{project}/apikeys/{name}](#delete-apiprojectsprojectapikeysname)
* [GET /api/projects/{project-id}/usage](#get-apiprojectsproject-idusage)
* [GET /api/projects/{project-id}/limit](#get-apiprojectsproject-idlimit)
* [Update limits](#update-limits)
* [POST /api/projects/{project-id}/limit?usage={value}](#post-apiprojectsproject-idlimitusagevalue)
* [POST /api/projects/{project-id}/limit?bandwidth={value}](#post-apiprojectsproject-idlimitbandwidthvalue)
* [POST /api/projects/{project-id}/limit?rate={value}](#post-apiprojectsproject-idlimitratevalue)
* [POST /api/projects/{project-id}/limit?buckets={value}](#post-apiprojectsproject-idlimitbucketsvalue)
* [APIKey Management](#apikey-management)
* [DELETE /api/apikeys/{apikey}](#delete-apiapikeysapikey)
* [API design](#api-design)
* [Error responses](#error-responses)
* [API Endpoints](#api-endpoints)
* [User Management](#user-management)
* [POST /api/users](#post-apiusers)
* [PUT /api/users/{user-email}](#put-apiusersuser-email)
* [GET /api/users/{user-email}](#get-apiusersuser-email)
* [DELETE /api/users/{user-email}](#delete-apiusersuser-email)
* [Coupon Management](#coupon-management)
* [POST /api/coupons](#post-apicoupons)
* [GET /api/coupons/{coupon-id}](#get-apicouponscoupon-id)
* [DELETE /api/coupons/{coupon-id}](#delete-apicouponscoupon-id)
* [Project Management](#project-management)
* [POST /api/projects](#post-apiprojects)
* [GET /api/projects/{project-id}](#get-apiprojectsproject-id)
* [PUT /api/projects/{project-id}](#put-apiprojectsproject-id)
* [DELETE /api/projects/{project-id}](#delete-apiprojectsproject-id)
* [GET /api/projects/{project}/apikeys](#get-apiprojectsprojectapikeys)
* [POST /api/projects/{project}/apikeys](#post-apiprojectsprojectapikeys)
* [DELETE /api/projects/{project}/apikeys/{name}](#delete-apiprojectsprojectapikeysname)
* [GET /api/projects/{project-id}/usage](#get-apiprojectsproject-idusage)
* [GET /api/projects/{project-id}/limit](#get-apiprojectsproject-idlimit)
* [Update limits](#update-limits)
* [POST /api/projects/{project-id}/limit?usage={value}](#post-apiprojectsproject-idlimitusagevalue)
* [POST /api/projects/{project-id}/limit?bandwidth={value}](#post-apiprojectsproject-idlimitbandwidthvalue)
* [POST /api/projects/{project-id}/limit?rate={value}](#post-apiprojectsproject-idlimitratevalue)
* [POST /api/projects/{project-id}/limit?buckets={value}](#post-apiprojectsproject-idlimitbucketsvalue)
* [APIKey Management](#apikey-management)
* [DELETE /api/apikeys/{apikey}](#delete-apiapikeysapikey)
<!-- tocstop -->
## User Management
## API design
### POST /api/users
### Error responses
When an API endpoint returns a client error (status code 4XX) it returns a JSON error response which contains 2 fields:
* `error`: The error message.
* `detail` (may be empty): Some detail about the returned error.
Example:
```json
{
"error": "usage for the current month exists",
"detail": ""
}
```
## API Endpoints
### User Management
#### POST /api/users
Adds a new user.
@ -64,7 +86,7 @@ A successful response body:
}
```
### PUT /api/users/{user-email}
#### PUT /api/users/{user-email}
Updates the details of existing user found by its email.
@ -89,7 +111,7 @@ Some example request bodies:
}
```
### GET /api/users/{user-email}
#### GET /api/users/{user-email}
This endpoint returns information about user and their projects.
@ -126,17 +148,17 @@ A successful response body:
}
```
### DELETE /api/users/{user-email}
#### DELETE /api/users/{user-email}
Deletes the user.
## Coupon Management
### Coupon Management
The coupons have an amount and duration.
Amount is expressed in cents of USD dollars (e.g. 500 is $5)
Duration is expressed in billing periods, a billing period is a natural month.
### POST /api/coupons
#### POST /api/coupons
Adds a coupon for specific user.
@ -159,7 +181,7 @@ A successful response body:
}
```
### GET /api/coupons/{coupon-id}
#### GET /api/coupons/{coupon-id}
Gets a coupon with the specified id.
@ -178,13 +200,13 @@ A successful response body:
}
```
### DELETE /api/coupons/{coupon-id}
#### DELETE /api/coupons/{coupon-id}
Deletes the specified coupon.
## Project Management
### Project Management
### POST /api/projects
#### POST /api/projects
Adds a project for specific user.
@ -205,11 +227,11 @@ A successful response body:
}
```
### GET /api/projects/{project-id}
#### GET /api/projects/{project-id}
Gets the common information about a project.
### PUT /api/projects/{project-id}
#### PUT /api/projects/{project-id}
Updates project name or description.
@ -220,11 +242,11 @@ Updates project name or description.
}
```
### DELETE /api/projects/{project-id}
#### DELETE /api/projects/{project-id}
Deletes the project.
### GET /api/projects/{project}/apikeys
#### GET /api/projects/{project}/apikeys
Get the list of the API keys of a specific project.
@ -249,7 +271,7 @@ A successful response body:
]
```
### POST /api/projects/{project}/apikeys
#### POST /api/projects/{project}/apikeys
Adds an apikey for specific project.
@ -271,17 +293,18 @@ A successful response body:
}
```
### DELETE /api/projects/{project}/apikeys/{name}
#### DELETE /api/projects/{project}/apikeys/{name}
Deletes the given apikey by its name.
### GET /api/projects/{project-id}/usage
#### GET /api/projects/{project-id}/usage
This endpoint returns whether the project has outstanding usage or not.
A project with not usage returns status code 200 and `{"result":"no project usage exist"}`.
Otherwise, it returns status code 409 with a JSON error.`{"error":"usage for current month exists""}`.
### GET /api/projects/{project-id}/limit
#### GET /api/projects/{project-id}/limit
This endpoint returns information about project limits.
@ -303,29 +326,29 @@ A successful response body:
}
```
### Update limits
#### Update limits
You can update the different limits with one single request just adding the
various query parameters (e.g. `usage=5000000&bandwidth=9000000`)
#### POST /api/projects/{project-id}/limit?usage={value}
##### POST /api/projects/{project-id}/limit?usage={value}
Updates usage limit for a project. The value must be in bytes.
#### POST /api/projects/{project-id}/limit?bandwidth={value}
##### POST /api/projects/{project-id}/limit?bandwidth={value}
Updates bandwidth limit for a project. The value must be in bytes.
#### POST /api/projects/{project-id}/limit?rate={value}
##### POST /api/projects/{project-id}/limit?rate={value}
Updates rate limit for a project.
#### POST /api/projects/{project-id}/limit?buckets={value}
##### POST /api/projects/{project-id}/limit?buckets={value}
Updates bucket limit for a project.
## APIKey Management
### APIKey Management
### DELETE /api/apikeys/{apikey}
#### DELETE /api/apikeys/{apikey}
Deletes the given apikey.

View File

@ -29,7 +29,7 @@ func TestAddApiKey(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -49,6 +49,7 @@ func TestAddApiKey(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -80,7 +81,7 @@ func TestDeleteApiKey(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -100,6 +101,7 @@ func TestDeleteApiKey(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -117,7 +119,7 @@ func TestDeleteApiKeyByName(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -136,6 +138,7 @@ func TestDeleteApiKeyByName(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -153,7 +156,7 @@ func TestListAPIKeys(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},

View File

@ -13,20 +13,25 @@ import (
// Error is default error class for admin package.
var Error = errs.Class("admin")
func httpJSONError(w http.ResponseWriter, error, detail string, statusCode int) {
func httpJSONError(w http.ResponseWriter, errMsg, detail string, statusCode int) {
errStr := struct {
Error string `json:"error"`
Detail string `json:"detail"`
}{
Error: error,
Error: errMsg,
Detail: detail,
}
byt, err := json.Marshal(errStr)
body, err := json.Marshal(errStr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(statusCode)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(byt) // any error here entitles a client side disconnect or similar, which we do not care about.
sendJSONData(w, statusCode, body)
}
func sendJSONData(w http.ResponseWriter, statusCode int, data []byte) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
_, _ = w.Write(data) // any error here entitles a client side disconnect or similar, which we do not care about.
}

View File

@ -27,7 +27,7 @@ func TestAddCoupon(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -44,6 +44,7 @@ func TestAddCoupon(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -69,7 +70,7 @@ func TestCouponInfo(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -89,6 +90,7 @@ func TestCouponInfo(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
@ -104,6 +106,7 @@ func TestCouponInfo(t *testing.T) {
response, err = http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err = ioutil.ReadAll(response.Body)
require.NoError(t, err)
@ -125,7 +128,7 @@ func TestCouponDelete(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -144,6 +147,7 @@ func TestCouponDelete(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
@ -165,6 +169,7 @@ func TestCouponDelete(t *testing.T) {
require.NoError(t, err)
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
coupons, err = planet.Satellites[0].DB.StripeCoinPayments().Coupons().ListByUserID(ctx, user.ID)
require.NoError(t, err)

View File

@ -32,7 +32,7 @@ func TestAPI(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -135,7 +135,7 @@ func TestAddProject(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -151,6 +151,7 @@ func TestAddProject(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -174,7 +175,7 @@ func TestRenameProject(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -195,6 +196,7 @@ func TestRenameProject(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
require.NoError(t, response.Body.Close())
project, err = planet.Satellites[0].DB.Console().Projects().Get(ctx, project.ID)
@ -209,7 +211,7 @@ func TestDeleteProject(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -239,6 +241,7 @@ func TestDeleteProject(t *testing.T) {
require.NoError(t, err)
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusConflict, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
err = planet.Satellites[0].DB.Console().APIKeys().Delete(ctx, apikeys.APIKeys[0].ID)
require.NoError(t, err)
@ -251,6 +254,7 @@ func TestDeleteProject(t *testing.T) {
require.NoError(t, err)
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
project, err := planet.Satellites[0].DB.Console().Projects().Get(ctx, projectID)
require.Error(t, err)
@ -264,7 +268,7 @@ func TestCheckUsageWithoutUsage(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -289,11 +293,12 @@ func TestCheckUsageWithoutUsage(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, "{\"result\":\"no project usage exist\"}", string(responseBody))
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusOK, response.StatusCode)
})
}
@ -303,7 +308,7 @@ func TestCheckUsageWithUsage(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -353,11 +358,13 @@ func TestCheckUsageWithUsage(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusConflict, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, "{\"error\":\"usage for current month exists\",\"detail\":\"\"}", string(responseBody))
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusConflict, response.StatusCode)
})
}
@ -367,7 +374,7 @@ func TestCheckUsageLastMonthUnappliedInvoice(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -429,11 +436,13 @@ func TestCheckUsageLastMonthUnappliedInvoice(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusConflict, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, "{\"error\":\"unapplied project invoice record exist\",\"detail\":\"\"}", string(responseBody))
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusConflict, response.StatusCode)
})
}
@ -443,7 +452,7 @@ func TestDeleteProjectWithUsageCurrentMonth(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -493,11 +502,13 @@ func TestDeleteProjectWithUsageCurrentMonth(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusConflict, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, "{\"error\":\"usage for current month exists\",\"detail\":\"\"}", string(responseBody))
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusConflict, response.StatusCode)
})
}
@ -507,7 +518,7 @@ func TestDeleteProjectWithUsagePreviousMonth(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},

View File

@ -4,6 +4,7 @@
package admin_test
import (
"io/ioutil"
"net/http"
"testing"
@ -37,7 +38,12 @@ func TestBasic(t *testing.T) {
require.NoError(t, err)
require.Equal(t, http.StatusForbidden, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
body, err := ioutil.ReadAll(response.Body)
require.NoError(t, response.Body.Close())
require.NoError(t, err)
require.Equal(t, `{"error":"Forbidden","detail":""}`, string(body))
})
t.Run("WrongAccess", func(t *testing.T) {
@ -49,7 +55,12 @@ func TestBasic(t *testing.T) {
require.NoError(t, err)
require.Equal(t, http.StatusForbidden, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
body, err := ioutil.ReadAll(response.Body)
require.NoError(t, response.Body.Close())
require.NoError(t, err)
require.Equal(t, `{"error":"Forbidden","detail":""}`, string(body))
})
t.Run("WithAccess", func(t *testing.T) {
@ -62,7 +73,12 @@ func TestBasic(t *testing.T) {
// currently no main page so 404
require.Equal(t, http.StatusNotFound, response.StatusCode)
require.Equal(t, "text/plain; charset=utf-8", response.Header.Get("Content-Type"))
body, err := ioutil.ReadAll(response.Body)
require.NoError(t, response.Body.Close())
require.NoError(t, err)
require.Contains(t, string(body), "not found")
})
})
}

View File

@ -67,5 +67,11 @@ func assertReq(
require.Equal(t, expectedBody, string(resBody), "response body")
}
if len(resBody) > 0 {
require.Equal(t, "application/json", res.Header.Get("Content-Type"))
} else {
require.Equal(t, "", res.Header.Get("Content-Type"))
}
return resBody
}

View File

@ -26,7 +26,7 @@ func TestGetUser(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -58,6 +58,8 @@ func TestGetUser(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
data, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
@ -75,7 +77,7 @@ func TestAddUser(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -91,6 +93,8 @@ func TestAddUser(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -112,7 +116,7 @@ func TestAddUserSameEmail(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -128,6 +132,8 @@ func TestAddUserSameEmail(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -150,6 +156,7 @@ func TestAddUserSameEmail(t *testing.T) {
response, err = http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusConflict, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
require.NoError(t, response.Body.Close())
})
}
@ -160,7 +167,7 @@ func TestUpdateUser(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -177,6 +184,7 @@ func TestUpdateUser(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -200,7 +208,7 @@ func TestUpdateUserRateLimit(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -219,6 +227,7 @@ func TestUpdateUserRateLimit(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -239,7 +248,7 @@ func TestDeleteUser(t *testing.T) {
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
@ -256,6 +265,7 @@ func TestDeleteUser(t *testing.T) {
response, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusConflict, response.StatusCode)
require.Equal(t, "application/json", response.Header.Get("Content-Type"))
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())
@ -272,6 +282,7 @@ func TestDeleteUser(t *testing.T) {
response, err = http.DefaultClient.Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, "", response.Header.Get("Content-Type"))
responseBody, err = ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.NoError(t, response.Body.Close())