Skip to content
Snippets Groups Projects
Unverified Commit 13fc0051 authored by jonastheis's avatar jonastheis
Browse files

Use client/lib to make HTTP requests in tester

parent 3eeb05ef
No related branches found
No related tags found
No related merge requests found
...@@ -28,7 +28,7 @@ var ( ...@@ -28,7 +28,7 @@ var (
const ( const (
routeBroadcastData = "broadcastData" routeBroadcastData = "broadcastData"
routeGetMessageById = "getMessageById" routeGetMessageById = "findMessageById"
routeGetNeighbors = "getNeighbors" routeGetNeighbors = "getNeighbors"
routeSpammer = "spammer" routeSpammer = "spammer"
routeLogin = "login" routeLogin = "login"
...@@ -39,15 +39,15 @@ const ( ...@@ -39,15 +39,15 @@ const (
func NewGoShimmerAPI(node string, httpClient ...http.Client) *GoShimmerAPI { func NewGoShimmerAPI(node string, httpClient ...http.Client) *GoShimmerAPI {
if len(httpClient) > 0 { if len(httpClient) > 0 {
return &GoShimmerAPI{node: node, httpClient: httpClient[0]} return &GoShimmerAPI{baseUrl: node, httpClient: httpClient[0]}
} }
return &GoShimmerAPI{node: node} return &GoShimmerAPI{baseUrl: node}
} }
// GoShimmerAPI is an API wrapper over the web API of GoShimmer. // GoShimmerAPI is an API wrapper over the web API of GoShimmer.
type GoShimmerAPI struct { type GoShimmerAPI struct {
httpClient http.Client httpClient http.Client
node string baseUrl string
jwt string jwt string
} }
...@@ -75,7 +75,7 @@ func interpretBody(res *http.Response, decodeTo interface{}) error { ...@@ -75,7 +75,7 @@ func interpretBody(res *http.Response, decodeTo interface{}) error {
case http.StatusInternalServerError: case http.StatusInternalServerError:
return fmt.Errorf("%w: %s", ErrInternalServerError, errRes.Error) return fmt.Errorf("%w: %s", ErrInternalServerError, errRes.Error)
case http.StatusNotFound: case http.StatusNotFound:
return fmt.Errorf("%w: %s", ErrNotFound, errRes.Error) return fmt.Errorf("%w: %s", ErrNotFound, res.Request.URL)
case http.StatusBadRequest: case http.StatusBadRequest:
return fmt.Errorf("%w: %s", ErrBadRequest, errRes.Error) return fmt.Errorf("%w: %s", ErrBadRequest, errRes.Error)
case http.StatusUnauthorized: case http.StatusUnauthorized:
...@@ -99,7 +99,7 @@ func (api *GoShimmerAPI) do(method string, route string, reqObj interface{}, res ...@@ -99,7 +99,7 @@ func (api *GoShimmerAPI) do(method string, route string, reqObj interface{}, res
} }
// construct request // construct request
req, err := http.NewRequest(method, fmt.Sprintf("%s/%s", api.node, route), func() io.Reader { req, err := http.NewRequest(method, fmt.Sprintf("%s/%s", api.baseUrl, route), func() io.Reader {
if data == nil { if data == nil {
return nil return nil
} }
...@@ -212,3 +212,7 @@ func (api *GoShimmerAPI) ToggleSpammer(enable bool) (*webapi_spammer.Response, e ...@@ -212,3 +212,7 @@ func (api *GoShimmerAPI) ToggleSpammer(enable bool) (*webapi_spammer.Response, e
} }
return res, nil return res, nil
} }
func (api *GoShimmerAPI) BaseUrl() string {
return api.baseUrl
}
package api
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
)
var (
ErrBadRequest = errors.New("bad request")
ErrInternalServerError = errors.New("internal server error")
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrUnknownError = errors.New("unknown error")
ErrNotImplemented = errors.New("operation not implemented/supported/available")
)
const (
routeBroadcastData = "broadcastData"
routeGetNeighbors = "getNeighbors"
routeGetMessageByHash = "getMessageByHash"
contentTypeJSON = "application/json"
)
func New(baseUrl string, httpClient http.Client) *Api {
return &Api{BaseUrl: baseUrl, httpClient: httpClient}
}
// Api is an API wrapper over the web API of GoShimmer.
type Api struct {
httpClient http.Client
BaseUrl string
jwt string
}
type errorResponse struct {
Error string `json:"error"`
}
func interpretBody(res *http.Response, decodeTo interface{}) error {
resBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("unable to read response body: %w", err)
}
defer res.Body.Close()
if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusCreated {
return json.Unmarshal(resBody, decodeTo)
}
errRes := &errorResponse{}
if err := json.Unmarshal(resBody, errRes); err != nil {
return fmt.Errorf("unable to read error from response body: %w", err)
}
switch res.StatusCode {
case http.StatusInternalServerError:
return fmt.Errorf("%w: %s", ErrInternalServerError, errRes.Error)
case http.StatusNotFound:
return fmt.Errorf("%w: %s", ErrNotFound, res.Request.URL.String())
case http.StatusBadRequest:
return fmt.Errorf("%w: %s", ErrBadRequest, errRes.Error)
case http.StatusUnauthorized:
return fmt.Errorf("%w: %s", ErrUnauthorized, errRes.Error)
case http.StatusNotImplemented:
return fmt.Errorf("%w: %s", ErrNotImplemented, errRes.Error)
}
return fmt.Errorf("%w: %s", ErrUnknownError, errRes.Error)
}
func (api *Api) do(method string, route string, reqObj interface{}, resObj interface{}) error {
// marshal request object
var data []byte
if reqObj != nil {
var err error
data, err = json.Marshal(reqObj)
if err != nil {
return err
}
}
// construct request
req, err := http.NewRequest(method, fmt.Sprintf("%s/%s", api.BaseUrl, route), func() io.Reader {
if data == nil {
return nil
}
return bytes.NewReader(data)
}())
if err != nil {
return err
}
if data != nil {
req.Header.Set("Content-Type", contentTypeJSON)
}
// add authorization header with JWT
if len(api.jwt) > 0 {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", api.jwt))
}
// make the request
res, err := api.httpClient.Do(req)
if err != nil {
return err
}
if resObj == nil {
return nil
}
// write response into response object
if err := interpretBody(res, resObj); err != nil {
return err
}
return nil
}
func (api *Api) BroadcastData(data string) (string, error) {
res := &BroadcastDataResponse{}
err := api.do(
http.MethodPost,
routeBroadcastData,
&BroadcastDataRequest{Data: data},
res,
)
if err != nil {
return "", err
}
return res.Hash, nil
}
// GetNeighbors gets the chosen/accepted neighbors.
// If knownPeers is set, also all known peers to the node are returned additionally.
func (api *Api) GetNeighbors(knownPeers bool) (*GetNeighborResponse, error) {
res := &GetNeighborResponse{}
err := api.do(
http.MethodGet,
func() string {
if !knownPeers {
return routeGetNeighbors
}
return fmt.Sprintf("%s?known=1", routeGetNeighbors)
}(),
nil,
res,
)
if err != nil {
return nil, err
}
return res, nil
}
func (api *Api) GetMessageByHash(hashes []string) (*GetMessageByHashResponse, error) {
res := &GetMessageByHashResponse{}
err := api.do(
http.MethodPost,
routeGetMessageByHash,
&GetMessageByHashRequest{Hashes: hashes},
res,
)
if err != nil {
return nil, err
}
return res, nil
}
package api
type BroadcastDataResponse struct {
Hash string `json:"hash,omitempty"`
Error string `json:"error,omitempty"`
}
type BroadcastDataRequest struct {
Data string `json:"data"`
}
type GetMessageByHashResponse struct {
Messages []Message `json:"messages,omitempty"`
Error string `json:"error,omitempty"`
}
type GetMessageByHashRequest struct {
Hashes []string `json:"hashes"`
}
type Message struct {
MessageId string `json:"messageId,omitempty"`
TrunkTransactionId string `json:"trunkTransactionId,omitempty"`
BranchTransactionId string `json:"branchTransactionId,omitempty"`
IssuerPublicKey string `json:"issuerPublicKey,omitempty"`
IssuingTime string `json:"issuingTime,omitempty"`
SequenceNumber uint64 `json:"sequenceNumber,omitempty"`
Payload string `json:"payload,omitempty"`
Signature string `json:"signature,omitempty"`
}
type GetNeighborResponse struct {
KnownPeers []Neighbor `json:"known,omitempty"`
Chosen []Neighbor `json:"chosen"`
Accepted []Neighbor `json:"accepted"`
Error string `json:"error,omitempty"`
}
type Neighbor struct {
ID string `json:"id"` // comparable node identifier
PublicKey string `json:"publicKey"` // public key used to verify signatures
Services []PeerService `json:"services,omitempty"`
}
type PeerService struct {
ID string `json:"id"` // ID of the service
Address string `json:"address"` // network address of the service
}
...@@ -9,42 +9,43 @@ import ( ...@@ -9,42 +9,43 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
"github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors"
"github.com/iotaledger/goshimmer/tools/integration-tests/tester/api" "github.com/iotaledger/goshimmer/client"
) )
type Peer struct { type Peer struct {
name string name string
ip net.IP ip net.IP
*api.Api *client.GoShimmerAPI
dockerCli *client.Client dockerCli *dockerclient.Client
chosen []api.Neighbor chosen []getNeighbors.Neighbor
accepted []api.Neighbor accepted []getNeighbors.Neighbor
} }
func NewPeer(name string, ip net.IP, dockerCli *client.Client) *Peer { func NewPeer(name string, ip net.IP, dockerCli *dockerclient.Client) *Peer {
return &Peer{ return &Peer{
name: name, name: name,
ip: ip, ip: ip,
Api: api.New(getWebApiBaseUrl(ip), http.Client{Timeout: 30 * time.Second}), GoShimmerAPI: client.NewGoShimmerAPI(getWebApiBaseUrl(ip), http.Client{Timeout: 30 * time.Second}),
dockerCli: dockerCli, dockerCli: dockerCli,
} }
} }
func (p *Peer) String() string { func (p *Peer) String() string {
return fmt.Sprintf("Peer:{%s, %s, %s, %d}", p.name, p.ip.String(), p.BaseUrl, p.TotalNeighbors()) return fmt.Sprintf("Peer:{%s, %s, %s, %d}", p.name, p.ip.String(), p.BaseUrl(), p.TotalNeighbors())
} }
func (p *Peer) TotalNeighbors() int { func (p *Peer) TotalNeighbors() int {
return len(p.chosen) + len(p.accepted) return len(p.chosen) + len(p.accepted)
} }
func (p *Peer) SetNeighbors(chosen, accepted []api.Neighbor) { func (p *Peer) SetNeighbors(chosen, accepted []getNeighbors.Neighbor) {
p.chosen = make([]api.Neighbor, len(chosen)) p.chosen = make([]getNeighbors.Neighbor, len(chosen))
copy(p.chosen, chosen) copy(p.chosen, chosen)
p.accepted = make([]api.Neighbor, len(accepted)) p.accepted = make([]getNeighbors.Neighbor, len(accepted))
copy(p.accepted, accepted) copy(p.accepted, accepted)
} }
...@@ -63,7 +64,7 @@ func (p *Peer) Logs() (io.ReadCloser, error) { ...@@ -63,7 +64,7 @@ func (p *Peer) Logs() (io.ReadCloser, error) {
}) })
} }
func getAvailablePeers(dockerCli *client.Client) (peers []*Peer) { func getAvailablePeers(dockerCli *dockerclient.Client) (peers []*Peer) {
// get peer master // get peer master
if addr, err := net.LookupIP(hostnamePeerMaster); err != nil { if addr, err := net.LookupIP(hostnamePeerMaster); err != nil {
fmt.Printf("Could not resolve %s\n", hostnamePeerMaster) fmt.Printf("Could not resolve %s\n", hostnamePeerMaster)
......
...@@ -6,18 +6,22 @@ import ( ...@@ -6,18 +6,22 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload"
) )
func TestRelayMessages(t *testing.T) { func TestRelayMessages(t *testing.T) {
numMessages := 100 numMessages := 100
hashes := make([]string, numMessages) ids := make([]string, numMessages)
data := payload.NewData([]byte("Test")).Bytes()
// create messages on random peers // create messages on random peers
for i := 0; i < numMessages; i++ { for i := 0; i < numMessages; i++ {
hash, err := f.RandomPeer().BroadcastData("Test") id, err := f.RandomPeer().BroadcastData(data)
require.NoError(t, err) require.NoError(t, err)
hashes[i] = hash ids[i] = id
} }
// wait for messages to be gossiped // wait for messages to be gossiped
...@@ -25,7 +29,7 @@ func TestRelayMessages(t *testing.T) { ...@@ -25,7 +29,7 @@ func TestRelayMessages(t *testing.T) {
// check for messages on every peer // check for messages on every peer
for _, peer := range f.Peers() { for _, peer := range f.Peers() {
resp, err := peer.GetMessageByHash(hashes) resp, err := peer.FindMessageById(ids)
require.NoError(t, err) require.NoError(t, err)
// check for the count of messages // check for the count of messages
...@@ -33,15 +37,15 @@ func TestRelayMessages(t *testing.T) { ...@@ -33,15 +37,15 @@ func TestRelayMessages(t *testing.T) {
// check that all messages are present in response // check that all messages are present in response
outer: outer:
for _, hash := range hashes { for _, id := range ids {
for _, msg := range resp.Messages { for _, msg := range resp.Messages {
// if message found skip to next // if message found skip to next
if msg.MessageId == hash { if msg.Id == id {
continue outer continue outer
} }
} }
t.Errorf("MessageId=%s not found in peer %s.", hash, peer.String()) t.Errorf("MessageId=%s not found in peer %s.", id, peer.String())
} }
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment