Skip to content
Snippets Groups Projects
Commit b8d1feb4 authored by Jake Taylor's avatar Jake Taylor
Browse files

added some tests

parent ae6a7c5e
No related branches found
No related tags found
3 merge requests!510Release,!214Project/restlike,!207WIP: Client Restructure
......@@ -7,6 +7,7 @@
package restlike
import (
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/cmix/identity/receptionID"
......@@ -22,6 +23,7 @@ type singleReceiver struct {
}
// Callback is the handler for single-use message reception for a RestServer
// Automatically responds to invalid endpoint requests
func (s *singleReceiver) Callback(req *single.Request, receptionId receptionID.EphemeralIdentity, rounds []rounds.Round) {
// Unmarshal the payload
newMessage := &Message{}
......@@ -31,22 +33,30 @@ func (s *singleReceiver) Callback(req *single.Request, receptionId receptionID.E
return
}
// Send the payload to the proper Callback
var respondErr error
if cb, err := s.endpoints.Get(URI(newMessage.GetUri()), Method(newMessage.GetMethod())); err == nil {
cb(newMessage)
// Send the payload to the proper Callback if it exists
respondErr = respond(cb(newMessage), req)
} else {
// If no callback, send an error response
responseMessage := &Message{Error: err.Error()}
payload, err := proto.Marshal(responseMessage)
if err != nil {
jww.ERROR.Printf("Unable to marshal restlike response message: %+v", err)
return
}
// Send the response
// TODO: Parameterize params and timeout
_, err = req.Respond(payload, cmix.GetDefaultCMIXParams(), 30*time.Second)
if err != nil {
jww.ERROR.Printf("Unable to send restlike response message: %+v", err)
}
// If no callback, automatically send an error response
respondErr = respond(&Message{Error: err.Error()}, req)
}
if respondErr != nil {
jww.ERROR.Printf("Unable to respond to request: %+v", err)
}
}
// respond to a single.Request with the given Message
func respond(response *Message, req *single.Request) error {
payload, err := proto.Marshal(response)
if err != nil {
return errors.Errorf("unable to marshal restlike response message: %+v", err)
}
// TODO: Parameterize params and timeout
_, err = req.Respond(payload, cmix.GetDefaultCMIXParams(), 30*time.Second)
if err != nil {
return errors.Errorf("unable to send restlike response message: %+v", err)
}
return nil
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package restlike
import (
"gitlab.com/elixxir/client/cmix/identity/receptionID"
"gitlab.com/elixxir/client/single"
"testing"
)
// Test failure of proto unmarshal
func TestSingleReceiver_Callback_FailUnmarshal(t *testing.T) {
ep := &Endpoints{endpoints: make(map[URI]map[Method]Callback)}
receiver := singleReceiver{endpoints: ep}
testReq := single.BuildTestRequest(make([]byte, 0), t)
receiver.Callback(testReq, receptionID.EphemeralIdentity{}, nil)
}
// Test happy path
//func TestSingleReceiver_Callback(t *testing.T) {
// ep := &Endpoints{endpoints: make(map[URI]map[Method]Callback)}
// resultChan := make(chan interface{}, 1)
// cb := func(*Message) *Message {
// resultChan <- ""
// return nil
// }
// testPath := URI("test/path")
// testMethod := Get
// testMessage := &Message{
// Content: []byte("test"),
// Headers: nil,
// Method: uint32(testMethod),
// Uri: string(testPath),
// Error: "",
// }
//
// err := ep.Add(testPath, testMethod, cb)
// if err != nil {
// t.Errorf(err.Error())
// }
// receiver := singleReceiver{endpoints: ep}
//
// testPayload, err := proto.Marshal(testMessage)
// if err != nil {
// t.Errorf(err.Error())
// }
// testReq := single.BuildTestRequest(testPayload, t)
// receiver.Callback(testReq, receptionID.EphemeralIdentity{}, nil)
//
// select {
// case _ = <-resultChan:
// case <-time.After(3 * time.Second):
// t.Errorf("Test SingleReceiver timed out!")
// }
//}
......@@ -64,7 +64,7 @@ func (s *SingleRequest) Request(method Method, recipient contact.Contact, path U
// AsyncRequest provides several Method of sending Data to the given URI
// and will return the Message to the given Callback when received
func (s *SingleRequest) AsyncRequest(method Method, recipient contact.Contact, path URI,
content Data, headers *Headers, cb Callback, singleParams single.RequestParams) error {
content Data, headers *Headers, cb RequestCallback, singleParams single.RequestParams) error {
// Build the Message
newMessage := &Message{
Content: content,
......
......@@ -14,7 +14,7 @@ import (
// processor is the response handler for a Request
type singleResponse struct {
responseCallback Callback
responseCallback RequestCallback
}
// Callback is the handler for single-use message responses for a Request
......
......@@ -21,9 +21,13 @@ type Data []byte
// Method defines the possible Request types
type Method uint32
// Callback provides the ability to make asynchronous Request
// RequestCallback provides the ability to make asynchronous Request
// in order to get the Message later without blocking
type Callback func(*Message)
type RequestCallback func(*Message)
// Callback serves as an Endpoint function to be called when a Request is received
// Should return the desired response to be sent back to the sender
type Callback func(*Message) *Message
const (
// Undefined default value
......@@ -98,12 +102,12 @@ func (e *Endpoints) Get(path URI, method Method) (Callback, error) {
// Remove an Endpoint
// Returns an error if Endpoint does not exist
func (e *Endpoints) Remove(path URI, method Method) error {
e.Lock()
defer e.Unlock()
if _, err := e.Get(path, method); err != nil {
return errors.Errorf("unable to UnregisterEndpoint: %s", err.Error())
}
e.Lock()
defer e.Unlock()
delete(e.endpoints[path], method)
if len(e.endpoints[path]) == 0 {
delete(e.endpoints, path)
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
package restlike
import "testing"
// Full test for all add/get/remove cases
func TestEndpoints(t *testing.T) {
ep := &Endpoints{endpoints: make(map[URI]map[Method]Callback)}
cb := func(*Message) *Message {
return nil
}
testPath := URI("test/path")
testMethod := Get
err := ep.Add(testPath, testMethod, cb)
if _, ok := ep.endpoints[testPath][testMethod]; err != nil || !ok {
t.Errorf("Failed to add endpoint: %+v", err)
}
err = ep.Add(testPath, testMethod, cb)
if _, ok := ep.endpoints[testPath][testMethod]; err == nil || !ok {
t.Errorf("Expected failure to add endpoint")
}
resultCb, err := ep.Get(testPath, testMethod)
if resultCb == nil || err != nil {
t.Errorf("Expected to get endpoint: %+v", err)
}
err = ep.Remove(testPath, testMethod)
if _, ok := ep.endpoints[testPath][testMethod]; err != nil || ok {
t.Errorf("Failed to remove endpoint: %+v", err)
}
err = ep.Remove(testPath, testMethod)
if _, ok := ep.endpoints[testPath][testMethod]; err == nil || ok {
t.Errorf("Expected failure to remove endpoint")
}
resultCb, err = ep.Get(testPath, testMethod)
if resultCb != nil || err == nil {
t.Errorf("Expected failure to get endpoint: %+v", err)
}
}
......@@ -18,6 +18,7 @@ import (
"gitlab.com/xx_network/primitives/id/ephemeral"
"sync"
"sync/atomic"
"testing"
"time"
)
......@@ -223,3 +224,17 @@ func splitPayload(payload []byte, maxSize, maxParts int) [][]byte {
}
return parts
}
// BuildTestRequest can be used for mocking a Request
func BuildTestRequest(payload []byte, t *testing.T) *Request {
return &Request{
sender: nil,
senderPubKey: nil,
dhKey: nil,
tag: "",
maxParts: 0,
used: nil,
requestPayload: payload,
net: nil,
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment