github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/private/engine/tessera/tessera_test.go (about)

     1  package tessera
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"net/url"
    10  	"os"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/kisexp/xdchain/common"
    15  	"github.com/kisexp/xdchain/private/engine"
    16  	testifyassert "github.com/stretchr/testify/assert"
    17  )
    18  
    19  var (
    20  	emptyHash                      = common.EncryptedPayloadHash{}
    21  	arbitraryHash                  = common.BytesToEncryptedPayloadHash([]byte("arbitrary"))
    22  	arbitraryHash1                 = common.BytesToEncryptedPayloadHash([]byte("arbitrary1"))
    23  	arbitraryNotFoundHash          = common.BytesToEncryptedPayloadHash([]byte("not found"))
    24  	arbitraryHashNoPrivateMetadata = common.BytesToEncryptedPayloadHash([]byte("no private extra data"))
    25  	arbitraryPrivatePayload        = []byte("arbitrary private payload")
    26  	arbitraryFrom                  = "arbitraryFrom"
    27  	arbitraryTo                    = []string{"arbitraryTo1", "arbitraryTo2"}
    28  	arbitraryMandatory             = []string{"arbitraryTo2"}
    29  	arbitraryPrivacyFlag           = engine.PrivacyFlagPartyProtection
    30  	arbitraryExtra                 = &engine.ExtraMetadata{
    31  		ACHashes:     Must(common.Base64sToEncryptedPayloadHashes([]string{arbitraryHash.ToBase64()})).(common.EncryptedPayloadHashes),
    32  		ACMerkleRoot: common.StringToHash("arbitrary root hash"),
    33  		PrivacyFlag:  arbitraryPrivacyFlag,
    34  	}
    35  	arbitraryExtraWithMandatoryFor = &engine.ExtraMetadata{
    36  		ACHashes:            Must(common.Base64sToEncryptedPayloadHashes([]string{arbitraryHash.ToBase64()})).(common.EncryptedPayloadHashes),
    37  		PrivacyFlag:         engine.PrivacyFlagMandatoryRecipients,
    38  		MandatoryRecipients: arbitraryMandatory,
    39  	}
    40  
    41  	testServer *httptest.Server
    42  	testObject *tesseraPrivateTxManager
    43  
    44  	sendRequestCaptor                    = make(chan *capturedRequest)
    45  	receiveRequestCaptor                 = make(chan *capturedRequest)
    46  	sendSignedTxRequestCaptor            = make(chan *capturedRequest)
    47  	sendSignedTxOctetStreamRequestCaptor = make(chan *capturedRequest)
    48  	getMandatoryRequestCaptor            = make(chan *capturedRequest)
    49  )
    50  
    51  type capturedRequest struct {
    52  	err     error
    53  	request interface{}
    54  	header  http.Header
    55  }
    56  
    57  func TestMain(m *testing.M) {
    58  	setup()
    59  	retCode := m.Run()
    60  	teardown()
    61  	os.Exit(retCode)
    62  }
    63  
    64  func Must(o interface{}, err error) interface{} {
    65  	if err != nil {
    66  		panic(fmt.Sprintf("%s", err))
    67  	}
    68  	return o
    69  }
    70  
    71  func setup() {
    72  	mux := http.NewServeMux()
    73  	mux.HandleFunc("/send", MockSendAPIHandlerFunc)
    74  	mux.HandleFunc("/transaction/", MockTransactionAPIHandlerFunc)
    75  	mux.HandleFunc("/sendsignedtx", MockSendSignedTxAPIHandlerFunc)
    76  	mux.HandleFunc("/groups/resident", MockGroupsAPIHandlerFunc)
    77  
    78  	testServer = httptest.NewServer(mux)
    79  
    80  	testObject = New(&engine.Client{
    81  		HttpClient: &http.Client{},
    82  		BaseURL:    testServer.URL,
    83  	}, []byte("2.0.0"))
    84  }
    85  
    86  func MockGroupsAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
    87  	var data []byte
    88  	data, _ = json.Marshal([]engine.PrivacyGroup{
    89  		{
    90  			Type:           "RESIDENT",
    91  			Name:           "RG1",
    92  			PrivacyGroupId: "RG1",
    93  			Description:    "Resident Group 1",
    94  			From:           "",
    95  			Members:        []string{"AAA", "BBB"},
    96  		},
    97  		{
    98  			Type:           "LEGACY",
    99  			Name:           "LEGACY1",
   100  			PrivacyGroupId: "LEGACY1",
   101  			Description:    "Legacy Group 1",
   102  			From:           "",
   103  			Members:        []string{"LEG1", "LEG2"},
   104  		},
   105  		{
   106  			Type:           "PANTHEON",
   107  			Name:           "P1",
   108  			PrivacyGroupId: "P1",
   109  			Description:    "Pantheon Group 1",
   110  			From:           "",
   111  			Members:        []string{"P1", "P2"},
   112  		},
   113  	})
   114  	response.Write(data)
   115  }
   116  
   117  func MockSendAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
   118  	actualRequest := new(sendRequest)
   119  	if err := json.NewDecoder(request.Body).Decode(actualRequest); err != nil {
   120  		go func(o *capturedRequest) { sendRequestCaptor <- o }(&capturedRequest{err: err})
   121  	} else {
   122  		go func(o *capturedRequest) { sendRequestCaptor <- o }(&capturedRequest{request: actualRequest, header: request.Header})
   123  		data, _ := json.Marshal(&sendResponse{
   124  			Key:            arbitraryHash.ToBase64(),
   125  			ManagedParties: []string{"ArbitraryPublicKey"},
   126  		})
   127  		response.Write(data)
   128  	}
   129  }
   130  
   131  func MockTransactionAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
   132  	if strings.HasSuffix(request.RequestURI, "/mandatory") {
   133  		MockGetMandatoryAPIHandlerFunc(response, request)
   134  	} else {
   135  		MockReceiveAPIHandlerFunc(response, request)
   136  	}
   137  }
   138  
   139  func MockGetMandatoryAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
   140  	actualRequest, err := url.PathUnescape(strings.TrimSuffix(strings.TrimPrefix(request.RequestURI, "/transaction/"), "/mandatory"))
   141  	if err != nil {
   142  		go func(o *capturedRequest) { getMandatoryRequestCaptor <- o }(&capturedRequest{err: err})
   143  	} else {
   144  		go func(o *capturedRequest) {
   145  			getMandatoryRequestCaptor <- o
   146  		}(&capturedRequest{request: actualRequest, header: request.Header})
   147  		if actualRequest == arbitraryNotFoundHash.ToBase64() {
   148  			response.WriteHeader(http.StatusNotFound)
   149  		} else {
   150  			response.Write([]byte(strings.Join(arbitraryMandatory, ",")))
   151  		}
   152  	}
   153  }
   154  
   155  func MockReceiveAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
   156  	path := string([]byte(request.RequestURI)[:strings.LastIndex(request.RequestURI, "?")])
   157  	actualRequest, err := url.PathUnescape(strings.TrimPrefix(path, "/transaction/"))
   158  	if err != nil {
   159  		go func(o *capturedRequest) { sendRequestCaptor <- o }(&capturedRequest{err: err})
   160  	} else {
   161  		go func(o *capturedRequest) {
   162  			receiveRequestCaptor <- o
   163  		}(&capturedRequest{request: actualRequest, header: request.Header})
   164  		if actualRequest == arbitraryNotFoundHash.ToBase64() {
   165  			response.WriteHeader(http.StatusNotFound)
   166  		} else {
   167  			var data []byte
   168  			if actualRequest == arbitraryHashNoPrivateMetadata.ToBase64() {
   169  				data, _ = json.Marshal(&receiveResponse{
   170  					Payload:        arbitraryPrivatePayload,
   171  					ManagedParties: []string{"ArbitraryPublicKey"},
   172  				})
   173  			} else {
   174  				data, _ = json.Marshal(&receiveResponse{
   175  					Payload:                      arbitraryPrivatePayload,
   176  					ExecHash:                     arbitraryExtra.ACMerkleRoot.ToBase64(),
   177  					AffectedContractTransactions: arbitraryExtra.ACHashes.ToBase64s(),
   178  					PrivacyFlag:                  arbitraryPrivacyFlag,
   179  					ManagedParties:               []string{"ArbitraryPublicKey"},
   180  				})
   181  			}
   182  			response.Write(data)
   183  		}
   184  	}
   185  }
   186  
   187  func MockSendSignedTxAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
   188  	actualRequest := new(sendSignedTxRequest)
   189  	if err := json.NewDecoder(request.Body).Decode(actualRequest); err != nil {
   190  		go func(o *capturedRequest) { sendSignedTxRequestCaptor <- o }(&capturedRequest{err: err})
   191  	} else {
   192  		go func(o *capturedRequest) { sendSignedTxRequestCaptor <- o }(&capturedRequest{request: actualRequest, header: request.Header})
   193  		data, _ := json.Marshal(&sendSignedTxResponse{
   194  			Key: arbitraryHash.ToBase64(),
   195  		})
   196  		response.Write(data)
   197  	}
   198  }
   199  
   200  func MockSendSignedTxOctetStreamAPIHandlerFunc(response http.ResponseWriter, request *http.Request) {
   201  	actualRequest := new(sendSignedTxRequest)
   202  	reqHash, err := ioutil.ReadAll(request.Body)
   203  	if err != nil {
   204  		go func(o *capturedRequest) { sendSignedTxOctetStreamRequestCaptor <- o }(&capturedRequest{err: err})
   205  		return
   206  	}
   207  	actualRequest.Hash = reqHash
   208  	actualRequest.To = strings.Split(request.Header["C11n-To"][0], ",")
   209  
   210  	go func(o *capturedRequest) { sendSignedTxOctetStreamRequestCaptor <- o }(&capturedRequest{request: actualRequest, header: request.Header})
   211  	response.Write([]byte(common.BytesToEncryptedPayloadHash(reqHash).ToBase64()))
   212  }
   213  
   214  func teardown() {
   215  	testServer.Close()
   216  }
   217  
   218  func verifyRequestHeader(h http.Header, t *testing.T) {
   219  	if h.Get("Content-type") != "application/json" {
   220  		t.Errorf("expected Content-type header is application/json")
   221  	}
   222  
   223  	if h.Get("Accept") != "application/json" {
   224  		t.Errorf("expected Accept header is application/json")
   225  	}
   226  }
   227  
   228  func verifyRequestHeaderMultiTenancy(h http.Header, t *testing.T) {
   229  	if h.Get("Content-type") != "application/vnd.tessera-2.1+json" {
   230  		t.Errorf("expected Content-type header is application/vnd.tessera-2.1+json")
   231  	}
   232  
   233  	if h.Get("Accept") != "application/vnd.tessera-2.1+json" {
   234  		t.Errorf("expected Accept header is application/vnd.tessera-2.1+json")
   235  	}
   236  }
   237  
   238  func verifyRequestHeaderMandatoryRecipients(h http.Header, t *testing.T) {
   239  	if h.Get("Content-type") != "application/vnd.tessera-4.0+json" {
   240  		t.Errorf("expected Content-type header is application/vnd.tessera-4.0+json")
   241  	}
   242  
   243  	if h.Get("Accept") != "application/vnd.tessera-4.0+json" {
   244  		t.Errorf("expected Accept header is application/vnd.tessera-4.0+json")
   245  	}
   246  }
   247  
   248  func TestSend_groups(t *testing.T) {
   249  	assert := testifyassert.New(t)
   250  
   251  	groups, err := testObject.Groups()
   252  	if err != nil {
   253  		t.Fatalf("%s", err)
   254  	}
   255  
   256  	assert.Len(groups, 3, "There should be three groups")
   257  
   258  	assert.Equal(groups[0].Name, "RG1")
   259  	assert.Equal(groups[0].PrivacyGroupId, "RG1")
   260  	assert.Equal(groups[0].Type, "RESIDENT")
   261  	assert.Exactly(groups[0].Members, []string{"AAA", "BBB"})
   262  
   263  	assert.Equal(groups[1].Name, "LEGACY1")
   264  	assert.Equal(groups[1].PrivacyGroupId, "LEGACY1")
   265  	assert.Equal(groups[1].Type, "LEGACY")
   266  	assert.Exactly(groups[1].Members, []string{"LEG1", "LEG2"})
   267  
   268  	assert.Equal(groups[2].Name, "P1")
   269  	assert.Equal(groups[2].PrivacyGroupId, "P1")
   270  	assert.Equal(groups[2].Type, "PANTHEON")
   271  	assert.Exactly(groups[2].Members, []string{"P1", "P2"})
   272  
   273  }
   274  
   275  func TestSend_whenTypical(t *testing.T) {
   276  	assert := testifyassert.New(t)
   277  
   278  	_, _, actualHash, err := testObject.Send(arbitraryPrivatePayload, arbitraryFrom, arbitraryTo, arbitraryExtra)
   279  	if err != nil {
   280  		t.Fatalf("%s", err)
   281  	}
   282  	capturedRequest := <-sendRequestCaptor
   283  
   284  	if capturedRequest.err != nil {
   285  		t.Fatalf("%s", capturedRequest.err)
   286  	}
   287  
   288  	verifyRequestHeader(capturedRequest.header, t)
   289  
   290  	actualRequest := capturedRequest.request.(*sendRequest)
   291  
   292  	assert.Equal(arbitraryPrivatePayload, actualRequest.Payload, "request.payload")
   293  	assert.Equal(arbitraryFrom, actualRequest.From, "request.from")
   294  	assert.Equal(arbitraryTo, actualRequest.To, "request.to")
   295  	assert.Equal(arbitraryPrivacyFlag, actualRequest.PrivacyFlag, "request.privacyFlag")
   296  	assert.Equal(arbitraryExtra.ACHashes.ToBase64s(), actualRequest.AffectedContractTransactions, "request.affectedContractTransactions")
   297  	assert.Equal(arbitraryExtra.ACMerkleRoot.ToBase64(), actualRequest.ExecHash, "request.execHash")
   298  	assert.Equal(arbitraryHash, actualHash, "returned hash")
   299  }
   300  
   301  func TestSend_whenTypical_MultiTenancy(t *testing.T) {
   302  	assert := testifyassert.New(t)
   303  
   304  	testObjectWithMT := New(&engine.Client{
   305  		HttpClient: &http.Client{},
   306  		BaseURL:    testServer.URL,
   307  	}, []byte("2.1"))
   308  
   309  	_, _, actualHash, err := testObjectWithMT.Send(arbitraryPrivatePayload, arbitraryFrom, arbitraryTo, arbitraryExtra)
   310  	if err != nil {
   311  		t.Fatalf("%s", err)
   312  	}
   313  	capturedRequest := <-sendRequestCaptor
   314  
   315  	if capturedRequest.err != nil {
   316  		t.Fatalf("%s", capturedRequest.err)
   317  	}
   318  
   319  	verifyRequestHeaderMultiTenancy(capturedRequest.header, t)
   320  
   321  	actualRequest := capturedRequest.request.(*sendRequest)
   322  
   323  	assert.Equal(arbitraryPrivatePayload, actualRequest.Payload, "request.payload")
   324  	assert.Equal(arbitraryFrom, actualRequest.From, "request.from")
   325  	assert.Equal(arbitraryTo, actualRequest.To, "request.to")
   326  	assert.Equal(arbitraryPrivacyFlag, actualRequest.PrivacyFlag, "request.privacyFlag")
   327  	assert.Equal(arbitraryExtra.ACHashes.ToBase64s(), actualRequest.AffectedContractTransactions, "request.affectedContractTransactions")
   328  	assert.Equal(arbitraryExtra.ACMerkleRoot.ToBase64(), actualRequest.ExecHash, "request.execHash")
   329  	assert.Equal(arbitraryHash, actualHash, "returned hash")
   330  }
   331  
   332  func TestSend_whenTesseraVersionDoesNotSupportPrivacyEnhancements(t *testing.T) {
   333  	assert := testifyassert.New(t)
   334  
   335  	testObjectNoPE := New(&engine.Client{
   336  		HttpClient: &http.Client{},
   337  		BaseURL:    testServer.URL,
   338  	}, []byte("0.10-SNAPSHOT"))
   339  
   340  	assert.False(testObjectNoPE.HasFeature(engine.PrivacyEnhancements), "the supplied version does not support privacy enhancements")
   341  
   342  	// trying to send a party protection transaction
   343  	_, _, _, err := testObjectNoPE.Send(arbitraryPrivatePayload, arbitraryFrom, arbitraryTo, arbitraryExtra)
   344  	if err != engine.ErrPrivateTxManagerDoesNotSupportPrivacyEnhancements {
   345  		t.Fatal("Expecting send to raise ErrPrivateTxManagerDoesNotSupportPrivacyEnhancements")
   346  	}
   347  }
   348  
   349  func TestSend_whenTypical_MandatoryRecipients(t *testing.T) {
   350  	assert := testifyassert.New(t)
   351  
   352  	testObjectWithMR := New(&engine.Client{
   353  		HttpClient: &http.Client{},
   354  		BaseURL:    testServer.URL,
   355  	}, []byte("4.0"))
   356  
   357  	_, _, actualHash, err := testObjectWithMR.Send(arbitraryPrivatePayload, arbitraryFrom, arbitraryTo, arbitraryExtraWithMandatoryFor)
   358  	if err != nil {
   359  		t.Fatalf("%s", err)
   360  	}
   361  	capturedRequest := <-sendRequestCaptor
   362  
   363  	if capturedRequest.err != nil {
   364  		t.Fatalf("%s", capturedRequest.err)
   365  	}
   366  
   367  	verifyRequestHeaderMandatoryRecipients(capturedRequest.header, t)
   368  
   369  	actualRequest := capturedRequest.request.(*sendRequest)
   370  
   371  	assert.Equal(arbitraryPrivatePayload, actualRequest.Payload, "request.payload")
   372  	assert.Equal(arbitraryFrom, actualRequest.From, "request.from")
   373  	assert.Equal(arbitraryTo, actualRequest.To, "request.to")
   374  	assert.Equal(engine.PrivacyFlagMandatoryRecipients, actualRequest.PrivacyFlag, "request.privacyFlag")
   375  	assert.Equal(arbitraryExtraWithMandatoryFor.ACHashes.ToBase64s(), actualRequest.AffectedContractTransactions, "request.affectedContractTransactions")
   376  	assert.Equal(arbitraryHash, actualHash, "returned hash")
   377  	assert.Equal(arbitraryMandatory, actualRequest.MandatoryRecipients, "request.mandatoryRecipients")
   378  }
   379  
   380  func TestSend_whenTesseraSupportEnhancedPrivacyButNotMandatoryRecipients(t *testing.T) {
   381  	assert := testifyassert.New(t)
   382  
   383  	testObjectNoMR := New(&engine.Client{
   384  		HttpClient: &http.Client{},
   385  		BaseURL:    testServer.URL,
   386  	}, []byte("3.0"))
   387  
   388  	assert.True(testObjectNoMR.HasFeature(engine.MultiTenancy))
   389  	assert.True(testObjectNoMR.HasFeature(engine.MultiplePrivateStates))
   390  	assert.False(testObjectNoMR.HasFeature(engine.MandatoryRecipients), "the supplied version does not support mandatory recipients")
   391  
   392  	// trying to send a mandatory recipients transaction
   393  	_, _, _, err := testObjectNoMR.Send(arbitraryPrivatePayload, arbitraryFrom, arbitraryTo, arbitraryExtraWithMandatoryFor)
   394  	if err != engine.ErrPrivateTxManagerDoesNotSupportMandatoryRecipients {
   395  		t.Fatal("Expecting send to raise ErrPrivateTxManagerDoesNotSupportMandatoryRecipients")
   396  	}
   397  }
   398  
   399  func TestSendRaw_whenTesseraVersionDoesNotSupportPrivacyEnhancements(t *testing.T) {
   400  	assert := testifyassert.New(t)
   401  
   402  	mux := http.NewServeMux()
   403  	mux.HandleFunc("/send", MockSendAPIHandlerFunc)
   404  	mux.HandleFunc("/transaction/", MockReceiveAPIHandlerFunc)
   405  	mux.HandleFunc("/sendsignedtx", MockSendSignedTxOctetStreamAPIHandlerFunc)
   406  
   407  	testServerNoPE := httptest.NewServer(mux)
   408  	defer testServerNoPE.Close()
   409  
   410  	testObjectNoPE := New(&engine.Client{
   411  		HttpClient: &http.Client{},
   412  		BaseURL:    testServerNoPE.URL,
   413  	}, []byte("0.10-SNAPSHOT"))
   414  
   415  	assert.False(testObjectNoPE.HasFeature(engine.PrivacyEnhancements), "the supplied version does not support privacy enhancements")
   416  
   417  	// trying to send a party protection transaction
   418  	_, _, _, err := testObjectNoPE.SendSignedTx(arbitraryHash, arbitraryTo, arbitraryExtra)
   419  	if err != engine.ErrPrivateTxManagerDoesNotSupportPrivacyEnhancements {
   420  		t.Fatal("Expecting send to raise ErrPrivateTxManagerDoesNotSupportPrivacyEnhancements")
   421  	}
   422  
   423  	// send a standard private transaction and check that the old version of the /sendsignedtx is used (using octetstream content type)
   424  
   425  	// caching incomplete item
   426  	_, _, _, err = testObjectNoPE.ReceiveRaw(arbitraryHashNoPrivateMetadata)
   427  	if err != nil {
   428  		t.Fatalf("%s", err)
   429  	}
   430  	<-receiveRequestCaptor
   431  
   432  	// caching complete item
   433  	_, _, _, err = testObjectNoPE.SendSignedTx(arbitraryHashNoPrivateMetadata, arbitraryTo, &engine.ExtraMetadata{
   434  		PrivacyFlag: engine.PrivacyFlagStandardPrivate})
   435  	if err != nil {
   436  		t.Fatalf("%s", err)
   437  	}
   438  	req := <-sendSignedTxOctetStreamRequestCaptor
   439  	assert.Equal("application/octet-stream", req.header["Content-Type"][0])
   440  
   441  	_, _, _, actualExtra, err := testObjectNoPE.Receive(arbitraryHashNoPrivateMetadata)
   442  	if err != nil {
   443  		t.Fatalf("%s", err)
   444  	}
   445  	assert.Equal(engine.PrivacyFlagStandardPrivate, actualExtra.PrivacyFlag, "cached privacy flag")
   446  
   447  }
   448  
   449  func TestReceive_whenTypical(t *testing.T) {
   450  	assert := testifyassert.New(t)
   451  
   452  	_, _, _, actualExtra, err := testObject.Receive(arbitraryHash1)
   453  	if err != nil {
   454  		t.Fatalf("%s", err)
   455  	}
   456  	capturedRequest := <-receiveRequestCaptor
   457  
   458  	if capturedRequest.err != nil {
   459  		t.Fatalf("%s", capturedRequest.err)
   460  	}
   461  
   462  	verifyRequestHeader(capturedRequest.header, t)
   463  
   464  	actualRequest := capturedRequest.request.(string)
   465  
   466  	assert.Equal(arbitraryHash1.ToBase64(), actualRequest, "requested hash")
   467  	assert.Equal(arbitraryExtra.ACHashes, actualExtra.ACHashes, "returned affected contract transaction hashes")
   468  	assert.Equal(arbitraryExtra.ACMerkleRoot, actualExtra.ACMerkleRoot, "returned merkle root")
   469  	assert.Equal(arbitraryExtra.PrivacyFlag, actualExtra.PrivacyFlag, "returned privacy flag")
   470  }
   471  
   472  func TestReceive_whenTypical_Multitenancy(t *testing.T) {
   473  	assert := testifyassert.New(t)
   474  
   475  	testObjectWithMT := New(&engine.Client{
   476  		HttpClient: &http.Client{},
   477  		BaseURL:    testServer.URL,
   478  	}, []byte("2.1"))
   479  
   480  	_, _, _, actualExtra, err := testObjectWithMT.Receive(arbitraryHash1)
   481  	if err != nil {
   482  		t.Fatalf("%s", err)
   483  	}
   484  	capturedRequest := <-receiveRequestCaptor
   485  
   486  	if capturedRequest.err != nil {
   487  		t.Fatalf("%s", capturedRequest.err)
   488  	}
   489  
   490  	verifyRequestHeaderMultiTenancy(capturedRequest.header, t)
   491  
   492  	actualRequest := capturedRequest.request.(string)
   493  
   494  	assert.Equal(arbitraryHash1.ToBase64(), actualRequest, "requested hash")
   495  	assert.Equal(arbitraryExtra.ACHashes, actualExtra.ACHashes, "returned affected contract transaction hashes")
   496  	assert.Equal(arbitraryExtra.ACMerkleRoot, actualExtra.ACMerkleRoot, "returned merkle root")
   497  	assert.Equal(arbitraryExtra.PrivacyFlag, actualExtra.PrivacyFlag, "returned privacy flag")
   498  }
   499  
   500  func TestReceive_whenPayloadNotFound(t *testing.T) {
   501  	assert := testifyassert.New(t)
   502  
   503  	_, _, data, _, err := testObject.Receive(arbitraryNotFoundHash)
   504  	if err != nil {
   505  		t.Fatalf("%s", err)
   506  	}
   507  	capturedRequest := <-receiveRequestCaptor
   508  
   509  	if capturedRequest.err != nil {
   510  		t.Fatalf("%s", capturedRequest.err)
   511  	}
   512  
   513  	verifyRequestHeader(capturedRequest.header, t)
   514  
   515  	actualRequest := capturedRequest.request.(string)
   516  
   517  	assert.Equal(arbitraryNotFoundHash.ToBase64(), actualRequest, "requested hash")
   518  	assert.Nil(data, "returned payload when not found")
   519  }
   520  
   521  func TestReceive_whenEncryptedPayloadHashIsEmpty(t *testing.T) {
   522  	assert := testifyassert.New(t)
   523  
   524  	_, _, data, _, err := testObject.Receive(emptyHash)
   525  	if err != nil {
   526  		t.Fatalf("%s", err)
   527  	}
   528  	assert.Empty(receiveRequestCaptor, "no request is actually sent")
   529  	assert.Nil(data, "returned payload when not found")
   530  }
   531  
   532  func TestReceive_whenHavingPayloadButNoPrivateExtraMetadata(t *testing.T) {
   533  	assert := testifyassert.New(t)
   534  
   535  	_, _, _, actualExtra, err := testObject.Receive(arbitraryHashNoPrivateMetadata)
   536  	if err != nil {
   537  		t.Fatalf("%s", err)
   538  	}
   539  	capturedRequest := <-receiveRequestCaptor
   540  
   541  	if capturedRequest.err != nil {
   542  		t.Fatalf("%s", capturedRequest.err)
   543  	}
   544  
   545  	verifyRequestHeader(capturedRequest.header, t)
   546  
   547  	actualRequest := capturedRequest.request.(string)
   548  
   549  	assert.Equal(arbitraryHashNoPrivateMetadata.ToBase64(), actualRequest, "requested hash")
   550  	assert.Empty(actualExtra.ACHashes, "returned affected contract transaction hashes")
   551  	assert.True(common.EmptyHash(actualExtra.ACMerkleRoot), "returned merkle root")
   552  }
   553  
   554  func TestSendSignedTx_whenTypical(t *testing.T) {
   555  	assert := testifyassert.New(t)
   556  
   557  	_, _, _, err := testObject.SendSignedTx(arbitraryHash, arbitraryTo, arbitraryExtra)
   558  	if err != nil {
   559  		t.Fatalf("%s", err)
   560  	}
   561  	capturedRequest := <-sendSignedTxRequestCaptor
   562  
   563  	if capturedRequest.err != nil {
   564  		t.Fatalf("%s", capturedRequest.err)
   565  	}
   566  
   567  	verifyRequestHeader(capturedRequest.header, t)
   568  
   569  	actualRequest := capturedRequest.request.(*sendSignedTxRequest)
   570  
   571  	assert.Equal(arbitraryTo, actualRequest.To, "request.to")
   572  	assert.Equal(arbitraryExtra.ACHashes.ToBase64s(), actualRequest.AffectedContractTransactions, "request.affectedContractTransactions")
   573  	assert.Equal(arbitraryExtra.ACMerkleRoot.ToBase64(), actualRequest.ExecHash, "request.execHash")
   574  }
   575  
   576  func TestSendSignedTx_whenTypical_MandatoryRecipients(t *testing.T) {
   577  	assert := testifyassert.New(t)
   578  
   579  	testObjectWithMR := New(&engine.Client{
   580  		HttpClient: &http.Client{},
   581  		BaseURL:    testServer.URL,
   582  	}, []byte("4.0"))
   583  
   584  	_, _, _, err := testObjectWithMR.SendSignedTx(arbitraryHash, arbitraryTo, arbitraryExtraWithMandatoryFor)
   585  	if err != nil {
   586  		t.Fatalf("%s", err)
   587  	}
   588  	capturedRequest := <-sendSignedTxRequestCaptor
   589  
   590  	if capturedRequest.err != nil {
   591  		t.Fatalf("%s", capturedRequest.err)
   592  	}
   593  
   594  	verifyRequestHeaderMandatoryRecipients(capturedRequest.header, t)
   595  
   596  	actualRequest := capturedRequest.request.(*sendSignedTxRequest)
   597  
   598  	assert.Equal(arbitraryTo, actualRequest.To, "request.to")
   599  	assert.Equal(arbitraryExtraWithMandatoryFor.ACHashes.ToBase64s(), actualRequest.AffectedContractTransactions, "request.affectedContractTransactions")
   600  	assert.Equal(engine.PrivacyFlagMandatoryRecipients, actualRequest.PrivacyFlag, "request.privacyFlag")
   601  	assert.Equal(arbitraryExtraWithMandatoryFor.MandatoryRecipients, actualRequest.MandatoryRecipients, "request.mandatoryRecipients")
   602  }
   603  
   604  func TestSendSignedTx_whenTesseraDoesNotSupportMandatoryRecipients(t *testing.T) {
   605  	assert := testifyassert.New(t)
   606  
   607  	testObjectNoMR := New(&engine.Client{
   608  		HttpClient: &http.Client{},
   609  		BaseURL:    testServer.URL,
   610  	}, []byte("3.0"))
   611  
   612  	assert.True(testObjectNoMR.HasFeature(engine.MultiTenancy))
   613  	assert.True(testObjectNoMR.HasFeature(engine.MultiplePrivateStates))
   614  	assert.False(testObjectNoMR.HasFeature(engine.MandatoryRecipients), "the supplied version does not support mandatory recipients")
   615  
   616  	// trying to send a mandatory recipients transaction
   617  	_, _, _, err := testObjectNoMR.SendSignedTx(arbitraryHash, arbitraryTo, arbitraryExtraWithMandatoryFor)
   618  	if err != engine.ErrPrivateTxManagerDoesNotSupportMandatoryRecipients {
   619  		t.Fatal("Expecting send to raise ErrPrivateTxManagerDoesNotSupportMandatoryRecipients")
   620  	}
   621  }
   622  
   623  func TestReceive_whenCachingRawPayload(t *testing.T) {
   624  	assert := testifyassert.New(t)
   625  
   626  	// caching incomplete item
   627  	_, _, _, err := testObject.ReceiveRaw(arbitraryHashNoPrivateMetadata)
   628  	if err != nil {
   629  		t.Fatalf("%s", err)
   630  	}
   631  	<-receiveRequestCaptor
   632  
   633  	// caching complete item
   634  	_, _, _, err = testObject.SendSignedTx(arbitraryHashNoPrivateMetadata, arbitraryTo, arbitraryExtra)
   635  	if err != nil {
   636  		t.Fatalf("%s", err)
   637  	}
   638  	<-sendSignedTxRequestCaptor
   639  
   640  	_, _, _, actualExtra, err := testObject.Receive(arbitraryHashNoPrivateMetadata)
   641  	if err != nil {
   642  		t.Fatalf("%s", err)
   643  	}
   644  
   645  	assert.Equal(arbitraryExtra.ACHashes, actualExtra.ACHashes, "cached affected contract transaction hashes")
   646  	assert.Equal(arbitraryExtra.ACMerkleRoot, actualExtra.ACMerkleRoot, "cached merkle root")
   647  	assert.Equal(arbitraryExtra.PrivacyFlag, actualExtra.PrivacyFlag, "cached privacy flag")
   648  }
   649  
   650  func TestGetMandatory_valid(t *testing.T) {
   651  	assert := testifyassert.New(t)
   652  
   653  	mandatoryRecipients, _ := testObject.GetMandatory(arbitraryHash)
   654  
   655  	assert.Equal(arbitraryMandatory, mandatoryRecipients)
   656  }
   657  
   658  func TestGetMandatory_notFound(t *testing.T) {
   659  	assert := testifyassert.New(t)
   660  
   661  	_, err := testObject.GetMandatory(arbitraryNotFoundHash)
   662  
   663  	assert.Error(err, "Non-200 status code")
   664  }