Skip to content
Snippets Groups Projects
Select Git revision
  • e3cf8ac9d02a5d0f26d6e9371a9e9f79c3c324cf
  • release default protected
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • hotfix/TestHostPool_UpdateNdf_AddFilter
  • XX-4719/announcementChannels
  • xx-4717/logLevel
  • jonah/noob-channel
  • master protected
  • XX-4707/tagDiskJson
  • xx-4698/notification-retry
  • hotfix/notifylockup
  • syncNodes
  • hotfix/localCB
  • XX-4677/NewChanManagerMobile
  • XX-4689/DmSync
  • duplicatePrefix
  • XX-4601/HavenInvites
  • finalizedUICallbacks
  • XX-4673/AdminKeySync
  • debugNotifID
  • anne/test
  • v4.7.5
  • v4.7.4
  • v4.7.3
  • v4.7.2
  • v4.7.1
  • v4.6.3
  • v4.6.1
  • v4.5.0
  • v4.4.4
  • v4.3.11
  • v4.3.8
  • v4.3.7
  • v4.3.6
  • v4.3.5
  • v4.2.0
  • v4.3.0
  • v4.3.4
  • v4.3.3
  • v4.3.2
  • v4.3.1
41 results

request_test.go

Blame
  • request_test.go 6.03 KiB
    ////////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                           //
    //                                                                            //
    // Use of this source code is governed by a license that can be found in the  //
    // LICENSE file                                                               //
    ////////////////////////////////////////////////////////////////////////////////
    
    package single
    
    import (
    	"bytes"
    	"fmt"
    	jww "github.com/spf13/jwalterweatherman"
    	"gitlab.com/elixxir/client/cmix"
    	"gitlab.com/elixxir/client/cmix/identity/receptionID"
    	"gitlab.com/elixxir/client/cmix/rounds"
    	"gitlab.com/elixxir/client/single/message"
    	"gitlab.com/elixxir/crypto/contact"
    	dh "gitlab.com/elixxir/crypto/diffieHellman"
    	"gitlab.com/elixxir/crypto/fastRNG"
    	"gitlab.com/xx_network/crypto/csprng"
    	"gitlab.com/xx_network/primitives/id"
    	"reflect"
    	"testing"
    	"time"
    )
    
    func TestGetMaxRequestSize(t *testing.T) {
    }
    
    type mockResponse struct {
    	payloadChan chan []byte
    }
    
    func (m mockResponse) Callback(
    	payload []byte, _ receptionID.EphemeralIdentity, _ []rounds.Round, _ error) {
    	m.payloadChan <- payload
    }
    
    type mockReceiver struct {
    	t           testing.TB
    	response    []byte
    	requestChan chan *Request
    }
    
    func (m *mockReceiver) Callback(
    	request *Request, _ receptionID.EphemeralIdentity, _ []rounds.Round) {
    	m.requestChan <- request
    	_, err := request.Respond(m.response, cmix.GetDefaultCMIXParams(), 0)
    	if err != nil {
    		m.t.Errorf("Failed to respond: %+v", err)
    	}
    }
    
    // Tests single-use request and response.
    func TestTransmitRequest(t *testing.T) {
    	jww.SetStdoutThreshold(jww.LevelDebug)
    	rng := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG).GetStream()
    	handler := newMockCmixHandler()
    	myID := id.NewIdFromString("myID", id.User, t)
    	net := newMockCmix(myID, handler, t)
    	grp := net.GetInstance().GetE2EGroup()
    
    	partnerPrivKey := dh.GeneratePrivateKey(dh.DefaultPrivateKeyLength, grp, rng)
    	partnerPubKey := dh.GeneratePublicKey(partnerPrivKey, grp)
    
    	recipient := contact.Contact{
    		ID:       id.NewIdFromString("recipient", id.User, t),
    		DhPubKey: partnerPubKey,
    	}
    
    	buff := bytes.NewBuffer(nil)
    	payloadSize := message.GetRequestPayloadSize(net.GetMaxMessageLength(),
    		grp.GetP().ByteLen())
    	requestSize := message.GetRequestContentsSize(payloadSize)
    	firstPart := make([]byte, requestSize)
    	copy(firstPart, "First part payload.")
    	buff.Write(firstPart)
    	requestPartSize := message.GetRequestPartContentsSize(
    		net.GetMaxMessageLength())
    
    	for i := 0; i < 10; i++ {
    		part := make([]byte, requestPartSize)
    		copy(part, fmt.Sprintf("Part #%d payload.", i))
    		buff.Write(part)
    	}
    	payload := buff.Bytes()
    
    	tag := "TestTransmitRequest"
    	responsePayload := make([]byte, 4096)
    	copy(responsePayload, "My response.")
    	responseChan := make(chan []byte, 10)
    	response := mockResponse{responseChan}
    	params := GetDefaultRequestParams()
    
    	requestChan := make(chan *Request, 10)
    	recipientNet := newMockCmix(recipient.ID, handler, t)
    	_ = Listen(tag, recipient.ID, partnerPrivKey, recipientNet, grp,
    		&mockReceiver{t, responsePayload, requestChan})
    
    	_, _, err := TransmitRequest(
    		recipient, tag, payload, response, params, net, rng, grp)
    	if err != nil {
    		t.Errorf("TransmitRequest returned an error: %+v", err)
    	}
    
    	select {
    	case r := <-requestChan:
    		if !bytes.Equal(r.GetPayload(), payload) {
    			t.Errorf("Received unexpected request payload."+
    				"\nexpected: %q\nreceived: %q", payload, r.GetPayload())
    		}
    	case <-time.After(30 * time.Millisecond):
    		t.Errorf("Timed out waiting to receive request.")
    	}
    
    	select {
    	case r := <-responseChan:
    		if !bytes.Equal(r, responsePayload) {
    			t.Errorf("Received unexpected response.\nexpected: %q\nreceived: %q",
    				payload, r)
    		}
    	case <-time.After(30 * time.Millisecond):
    		t.Errorf("Timed out waiting to receive response.")
    	}
    }
    
    // Tests that waitForTimeout returns and does not call the callback when the
    // kill channel is used.
    func Test_waitForTimeout(t *testing.T) {
    	timeout := 15 * time.Millisecond
    	cbChan := make(chan error, 1)
    	cb := func(
    		_ []byte, _ receptionID.EphemeralIdentity, _ []rounds.Round, err error) {
    		cbChan <- err
    	}
    	killChan := make(chan bool, 1)
    
    	go func() {
    		time.Sleep(timeout / 2)
    		killChan <- true
    	}()
    
    	waitForTimeout(killChan, cb, timeout)
    
    	select {
    	case <-cbChan:
    		t.Error("Callback called when waitForTimeout should have been killed.")
    	case <-time.After(timeout):
    	}
    }
    
    // Error path: tests that waitForTimeout returns an error on the callback when
    // the timeout is reached.
    func Test_waitForTimeout_TimeoutError(t *testing.T) {
    	timeout := 15 * time.Millisecond
    	expectedErr := fmt.Sprintf(errResponseTimeout, timeout)
    	cbChan := make(chan error)
    	cb := func(
    		_ []byte, _ receptionID.EphemeralIdentity, _ []rounds.Round, err error) {
    		cbChan <- err
    	}
    	killChan := make(chan bool)
    
    	go waitForTimeout(killChan, cb, timeout)
    
    	select {
    	case r := <-cbChan:
    		if r == nil || r.Error() != expectedErr {
    			t.Errorf("Did not get expected error on callback."+
    				"\nexpected: %s\nreceived: %+v", expectedErr, r)
    		}
    	case <-time.After(timeout * 2):
    		t.Errorf("Timed out waiting on callback.")
    	}
    }
    
    // Builds a payload alongside the expected first part and list of subsequent
    // parts and tests that partitionPayload properly partitions the payload into
    // the expected parts.
    func Test_partitionPayload(t *testing.T) {
    	const partSize = 16
    	expectedFirstPart := []byte("first part")
    	expectedParts := make([][]byte, 10)
    	payload := bytes.NewBuffer(expectedFirstPart)
    	for i := range expectedParts {
    		expectedParts[i] = make([]byte, partSize)
    		copy(expectedParts[i], fmt.Sprintf("Part #%d", i))
    		payload.Write(expectedParts[i])
    	}
    
    	firstPart, parts := partitionPayload(
    		len(expectedFirstPart), partSize, payload.Bytes())
    
    	if !bytes.Equal(expectedFirstPart, firstPart) {
    		t.Errorf("Received unexpected first part.\nexpected: %q\nreceived: %q",
    			expectedFirstPart, firstPart)
    	}
    
    	if !reflect.DeepEqual(expectedParts, parts) {
    		t.Errorf("Received unexpected parts.\nexpected: %q\nreceived: %q",
    			expectedParts, parts)
    	}
    }