github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/mock_test.go (about) 1 //go:build all || unit 2 // +build all unit 3 4 package hedera 5 6 /*- 7 * 8 * Hedera Go SDK 9 * 10 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC 11 * 12 * Licensed under the Apache License, Version 2.0 (the "License"); 13 * you may not use this file except in compliance with the License. 14 * You may obtain a copy of the License at 15 * 16 * http://www.apache.org/licenses/LICENSE-2.0 17 * 18 * Unless required by applicable law or agreed to in writing, software 19 * distributed under the License is distributed on an "AS IS" BASIS, 20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 * See the License for the specific language governing permissions and 22 * limitations under the License. 23 * 24 */ 25 26 import ( 27 "context" 28 "net" 29 "testing" 30 "time" 31 32 "github.com/hashgraph/hedera-protobufs-go/mirror" 33 "google.golang.org/grpc/codes" 34 "google.golang.org/grpc/status" 35 36 "github.com/stretchr/testify/require" 37 protobuf "google.golang.org/protobuf/proto" 38 39 "github.com/hashgraph/hedera-protobufs-go/services" 40 "google.golang.org/grpc" 41 ) 42 43 func TestUnitMockQuery(t *testing.T) { 44 t.Parallel() 45 responses := [][]interface{}{ 46 { 47 &services.Response{ 48 Response: &services.Response_CryptogetAccountBalance{ 49 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 50 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 51 }, 52 }, 53 }, 54 &services.Response{ 55 Response: &services.Response_CryptogetAccountBalance{ 56 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 57 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 58 }, 59 }, 60 }, 61 &services.Response{ 62 Response: &services.Response_CryptogetAccountBalance{ 63 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 64 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 65 }, 66 }, 67 }, 68 &services.Response{ 69 Response: &services.Response_CryptogetAccountBalance{ 70 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 71 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 72 }, 73 }, 74 }, 75 &services.Response{ 76 Response: &services.Response_CryptogetAccountBalance{ 77 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 78 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 79 }, 80 }, 81 }, 82 &services.Response{ 83 Response: &services.Response_CryptogetAccountBalance{ 84 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 85 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 86 }, 87 }, 88 }, 89 &services.Response{ 90 Response: &services.Response_CryptogetAccountBalance{ 91 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 92 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, ResponseType: services.ResponseType_ANSWER_ONLY}, 93 }, 94 }, 95 }, 96 &services.Response{ 97 Response: &services.Response_CryptogetAccountBalance{ 98 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 99 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, ResponseType: services.ResponseType_COST_ANSWER, Cost: 0}, 100 AccountID: &services.AccountID{ShardNum: 0, RealmNum: 0, Account: &services.AccountID_AccountNum{ 101 AccountNum: 1800, 102 }}, 103 Balance: 2000, 104 }, 105 }, 106 }, 107 &services.Response{ 108 Response: &services.Response_CryptogetAccountBalance{ 109 CryptogetAccountBalance: &services.CryptoGetAccountBalanceResponse{ 110 Header: &services.ResponseHeader{NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, ResponseType: services.ResponseType_ANSWER_ONLY, Cost: 0}, 111 AccountID: &services.AccountID{ShardNum: 0, RealmNum: 0, Account: &services.AccountID_AccountNum{ 112 AccountNum: 1800, 113 }}, 114 Balance: 2000, 115 }, 116 }, 117 }, 118 }, 119 } 120 121 client, server := NewMockClientAndServer(responses) 122 defer server.Close() 123 124 _, err := NewAccountBalanceQuery(). 125 SetNodeAccountIDs([]AccountID{{Account: 3}}). 126 SetAccountID(AccountID{Account: 1800}). 127 Execute(client) 128 require.NoError(t, err) 129 } 130 131 func DisabledTestUnitMockBackoff(t *testing.T) { 132 responses := [][]interface{}{{ 133 &services.TransactionResponse{ 134 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 135 }, 136 &services.TransactionResponse{ 137 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 138 }, 139 &services.TransactionResponse{ 140 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 141 }, 142 &services.TransactionResponse{ 143 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 144 }, 145 }, { 146 &services.TransactionResponse{ 147 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 148 }, 149 &services.TransactionResponse{ 150 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 151 }, 152 &services.TransactionResponse{ 153 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 154 }, 155 &services.TransactionResponse{ 156 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 157 }, 158 &services.TransactionResponse{ 159 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 160 }, 161 }} 162 163 client, server := NewMockClientAndServer(responses) 164 defer server.Close() 165 166 newKey, err := PrivateKeyGenerateEd25519() 167 require.NoError(t, err) 168 169 newBalance := NewHbar(2) 170 171 tran := TransactionIDGenerate(AccountID{Account: 3}) 172 173 _, err = NewAccountCreateTransaction(). 174 SetNodeAccountIDs([]AccountID{{Account: 3}, {Account: 4}}). 175 SetKey(newKey). 176 SetTransactionID(tran). 177 SetInitialBalance(newBalance). 178 SetMaxAutomaticTokenAssociations(100). 179 Execute(client) 180 require.NoError(t, err) 181 } 182 183 func TestUnitMockAddressBookQuery(t *testing.T) { 184 t.Parallel() 185 responses := [][]interface{}{{ 186 &services.NodeAddress{ 187 RSA_PubKey: "", 188 NodeId: 0, 189 NodeAccountId: &services.AccountID{ 190 ShardNum: 0, 191 RealmNum: 0, 192 Account: &services.AccountID_AccountNum{AccountNum: 3}, 193 }, 194 NodeCertHash: []byte{1}, 195 ServiceEndpoint: []*services.ServiceEndpoint{ 196 { 197 IpAddressV4: []byte{byte(uint(1)), byte(uint(2)), byte(uint(2)), byte(uint(3))}, 198 Port: 50123, 199 DomainName: "hedera.domain.name", 200 }, 201 { 202 IpAddressV4: []byte{byte(uint(2)), byte(uint(1)), byte(uint(2)), byte(uint(3))}, 203 Port: 50123, 204 DomainName: "hedera.domain.name", 205 }, 206 }, 207 Description: "", 208 Stake: 0, 209 }, 210 &services.NodeAddress{ 211 RSA_PubKey: "", 212 NodeId: 0, 213 NodeAccountId: &services.AccountID{ 214 ShardNum: 0, 215 RealmNum: 0, 216 Account: &services.AccountID_AccountNum{AccountNum: 4}, 217 }, 218 NodeCertHash: []byte{1}, 219 ServiceEndpoint: []*services.ServiceEndpoint{ 220 { 221 IpAddressV4: []byte{byte(uint(1)), byte(uint(2)), byte(uint(2)), byte(uint(9))}, 222 Port: 50123, 223 DomainName: "hedera.domain.name2", 224 }, 225 { 226 IpAddressV4: []byte{byte(uint(2)), byte(uint(1)), byte(uint(2)), byte(uint(9))}, 227 Port: 50123, 228 DomainName: "hedera.domain.name2", 229 }, 230 }, 231 Description: "", 232 Stake: 0, 233 }, 234 }, 235 } 236 237 client, server := NewMockClientAndServer(responses) 238 defer server.Close() 239 240 result, err := NewAddressBookQuery(). 241 SetFileID(FileID{0, 0, 101, nil}). 242 Execute(client) 243 require.NoError(t, err) 244 245 require.Equal(t, len(result.NodeAddresses), 2) 246 require.Equal(t, result.NodeAddresses[0].AccountID.String(), "0.0.3") 247 require.Equal(t, result.NodeAddresses[0].Addresses[0].String(), "hedera.domain.name:50123") 248 require.Equal(t, result.NodeAddresses[0].Addresses[1].String(), "hedera.domain.name:50123") 249 require.Equal(t, result.NodeAddresses[1].AccountID.String(), "0.0.4") 250 require.Equal(t, result.NodeAddresses[1].Addresses[0].String(), "hedera.domain.name2:50123") 251 require.Equal(t, result.NodeAddresses[1].Addresses[1].String(), "hedera.domain.name2:50123") 252 } 253 254 func TestUnitMockGenerateTransactionIDsPerExecution(t *testing.T) { 255 t.Parallel() 256 count := 0 257 transactionIds := make(map[string]bool) 258 259 call := func(request *services.Transaction) *services.TransactionResponse { 260 var response *services.TransactionResponse 261 require.NotEmpty(t, request.SignedTransactionBytes) 262 signedTransaction := services.SignedTransaction{} 263 _ = protobuf.Unmarshal(request.SignedTransactionBytes, &signedTransaction) 264 265 require.NotEmpty(t, signedTransaction.BodyBytes) 266 transactionBody := services.TransactionBody{} 267 _ = protobuf.Unmarshal(signedTransaction.BodyBytes, &transactionBody) 268 269 require.NotNil(t, transactionBody.TransactionID) 270 transactionId := transactionBody.TransactionID.String() 271 require.NotEqual(t, "", transactionId) 272 if count < 2 { 273 require.False(t, transactionIds[transactionId]) 274 } 275 transactionIds[transactionId] = true 276 277 sigMap := signedTransaction.GetSigMap() 278 require.NotNil(t, sigMap) 279 require.NotEqual(t, 0, len(sigMap.SigPair)) 280 281 for _, sigPair := range sigMap.SigPair { 282 verified := false 283 284 switch k := sigPair.Signature.(type) { 285 case *services.SignaturePair_Ed25519: 286 pbTemp, _ := PublicKeyFromBytesEd25519(sigPair.PubKeyPrefix) 287 verified = pbTemp.Verify(signedTransaction.BodyBytes, k.Ed25519) 288 case *services.SignaturePair_ECDSASecp256K1: 289 pbTemp, _ := PublicKeyFromBytesECDSA(sigPair.PubKeyPrefix) 290 verified = pbTemp.Verify(signedTransaction.BodyBytes, k.ECDSASecp256K1) 291 } 292 require.True(t, verified) 293 } 294 295 if count < 2 { 296 response = &services.TransactionResponse{ 297 NodeTransactionPrecheckCode: services.ResponseCodeEnum_TRANSACTION_EXPIRED, 298 } 299 } else { 300 response = &services.TransactionResponse{ 301 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 302 } 303 } 304 305 count += 1 306 307 return response 308 } 309 responses := [][]interface{}{{ 310 call, call, call, 311 }} 312 313 client, server := NewMockClientAndServer(responses) 314 defer server.Close() 315 316 _, err := NewFileCreateTransaction(). 317 SetNodeAccountIDs([]AccountID{{Account: 3}}). 318 SetContents([]byte("hello")). 319 Execute(client) 320 require.NoError(t, err) 321 } 322 323 func TestUnitMockSingleTransactionIDForExecutions(t *testing.T) { 324 t.Parallel() 325 count := 0 326 tran := TransactionIDGenerate(AccountID{Account: 1800}) 327 transactionIds := make(map[string]bool) 328 transactionIds[tran._ToProtobuf().String()] = true 329 330 call := func(request *services.Transaction) *services.TransactionResponse { 331 var response *services.TransactionResponse 332 333 require.NotEmpty(t, request.SignedTransactionBytes) 334 signedTransaction := services.SignedTransaction{} 335 _ = protobuf.Unmarshal(request.SignedTransactionBytes, &signedTransaction) 336 337 require.NotEmpty(t, signedTransaction.BodyBytes) 338 transactionBody := services.TransactionBody{} 339 _ = protobuf.Unmarshal(signedTransaction.BodyBytes, &transactionBody) 340 341 require.NotNil(t, transactionBody.TransactionID) 342 transactionId := transactionBody.TransactionID.String() 343 require.NotEqual(t, "", transactionId) 344 require.True(t, transactionIds[transactionId]) 345 transactionIds[transactionId] = true 346 347 sigMap := signedTransaction.GetSigMap() 348 require.NotNil(t, sigMap) 349 require.NotEqual(t, 0, len(sigMap.SigPair)) 350 351 for _, sigPair := range sigMap.SigPair { 352 verified := false 353 354 switch k := sigPair.Signature.(type) { 355 case *services.SignaturePair_Ed25519: 356 pbTemp, _ := PublicKeyFromBytesEd25519(sigPair.PubKeyPrefix) 357 verified = pbTemp.Verify(signedTransaction.BodyBytes, k.Ed25519) 358 case *services.SignaturePair_ECDSASecp256K1: 359 pbTemp, _ := PublicKeyFromBytesECDSA(sigPair.PubKeyPrefix) 360 verified = pbTemp.Verify(signedTransaction.BodyBytes, k.ECDSASecp256K1) 361 } 362 require.True(t, verified) 363 } 364 365 if count < 2 { 366 response = &services.TransactionResponse{ 367 NodeTransactionPrecheckCode: services.ResponseCodeEnum_BUSY, 368 } 369 } else { 370 response = &services.TransactionResponse{ 371 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 372 } 373 } 374 375 count += 1 376 377 return response 378 } 379 responses := [][]interface{}{{ 380 call, call, call, 381 }} 382 383 client, server := NewMockClientAndServer(responses) 384 defer server.Close() 385 386 _, err := NewFileCreateTransaction(). 387 SetNodeAccountIDs([]AccountID{{Account: 3}}). 388 SetTransactionID(tran). 389 SetContents([]byte("hello")). 390 Execute(client) 391 require.NoError(t, err) 392 } 393 394 func TestUnitMockSingleTransactionIDForExecutionsWithTimeout(t *testing.T) { 395 t.Parallel() 396 count := 0 397 tran := TransactionIDGenerate(AccountID{Account: 1800}) 398 transactionIds := make(map[string]bool) 399 transactionIds[tran._ToProtobuf().String()] = true 400 401 call := func(request *services.Transaction) *services.TransactionResponse { 402 var response *services.TransactionResponse 403 404 require.NotEmpty(t, request.SignedTransactionBytes) 405 signedTransaction := services.SignedTransaction{} 406 _ = protobuf.Unmarshal(request.SignedTransactionBytes, &signedTransaction) 407 408 require.NotEmpty(t, signedTransaction.BodyBytes) 409 transactionBody := services.TransactionBody{} 410 _ = protobuf.Unmarshal(signedTransaction.BodyBytes, &transactionBody) 411 412 require.NotNil(t, transactionBody.TransactionID) 413 transactionId := transactionBody.TransactionID.String() 414 require.NotEqual(t, "", transactionId) 415 require.True(t, transactionIds[transactionId]) 416 transactionIds[transactionId] = true 417 418 sigMap := signedTransaction.GetSigMap() 419 require.NotNil(t, sigMap) 420 require.NotEqual(t, 0, len(sigMap.SigPair)) 421 422 for _, sigPair := range sigMap.SigPair { 423 verified := false 424 425 switch k := sigPair.Signature.(type) { 426 case *services.SignaturePair_Ed25519: 427 pbTemp, _ := PublicKeyFromBytesEd25519(sigPair.PubKeyPrefix) 428 verified = pbTemp.Verify(signedTransaction.BodyBytes, k.Ed25519) 429 case *services.SignaturePair_ECDSASecp256K1: 430 pbTemp, _ := PublicKeyFromBytesECDSA(sigPair.PubKeyPrefix) 431 verified = pbTemp.Verify(signedTransaction.BodyBytes, k.ECDSASecp256K1) 432 } 433 require.True(t, verified) 434 } 435 436 if count < 2 { 437 response = &services.TransactionResponse{ 438 NodeTransactionPrecheckCode: services.ResponseCodeEnum_TRANSACTION_EXPIRED, 439 } 440 } else { 441 response = &services.TransactionResponse{ 442 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 443 } 444 } 445 446 count += 1 447 448 return response 449 } 450 responses := [][]interface{}{{ 451 call, call, call, 452 }} 453 454 client, server := NewMockClientAndServer(responses) 455 defer server.Close() 456 457 _, err := NewFileCreateTransaction(). 458 SetTransactionID(tran). 459 SetContents([]byte("hello")). 460 Execute(client) 461 require.Error(t, err) 462 } 463 464 type MockServers struct { 465 servers []*MockServer 466 } 467 468 func (servers *MockServers) Close() { 469 for _, server := range servers.servers { 470 if server != nil { 471 server.Close() 472 } 473 } 474 } 475 476 func NewMockClientAndServer(allNodeResponses [][]interface{}) (*Client, *MockServers) { 477 network := map[string]AccountID{} 478 mirrorNetwork := make([]string, len(allNodeResponses)) 479 servers := make([]*MockServer, len(allNodeResponses)) 480 ctx, cancel := context.WithCancel(context.Background()) 481 482 logger := NewLogger("hedera client mock", LoggerLevelError) 483 var defaultLogger Logger = logger 484 485 client := &Client{ 486 defaultMaxQueryPayment: NewHbar(1), 487 network: _NewNetwork(), 488 mirrorNetwork: _NewMirrorNetwork(), 489 autoValidateChecksums: false, 490 maxAttempts: nil, 491 minBackoff: 250 * time.Millisecond, 492 maxBackoff: 8 * time.Second, 493 defaultRegenerateTransactionIDs: true, 494 defaultNetworkUpdatePeriod: 24 * time.Hour, 495 networkUpdateContext: ctx, 496 cancelNetworkUpdate: cancel, 497 logger: defaultLogger, 498 } 499 500 for i, responses := range allNodeResponses { 501 responses := responses 502 503 serverReady := make(chan bool) 504 nodeAccountID := AccountID{Account: uint64(3 + i)} 505 go func() { 506 servers[i] = NewMockServer(responses) 507 serverReady <- true 508 }() 509 510 <-serverReady 511 512 network[servers[i].listener.Addr().String()] = nodeAccountID 513 mirrorNetwork[i] = servers[i].listener.Addr().String() 514 } 515 516 client.SetNetwork(network) 517 client.SetLedgerID(*NewLedgerIDMainnet()) 518 client.SetMirrorNetwork(mirrorNetwork) 519 520 key, _ := PrivateKeyFromStringEd25519("302e020100300506032b657004220420d45e1557156908c967804615af59a000be88c7aa7058bfcbe0f46b16c28f887d") 521 client.SetOperator(AccountID{Account: 1800}, key) 522 client.SetMinBackoff(0) 523 client.SetMaxBackoff(0) 524 client.SetMinNodeReadmitTime(0) 525 client.SetMaxNodeReadmitTime(0) 526 client.SetNodeMinBackoff(0) 527 client.SetNodeMaxBackoff(0) 528 529 return client, &MockServers{servers} 530 } 531 532 func TestUnitMockAccountInfoQuery(t *testing.T) { 533 t.Skip("Skipping test as it is currently broken with the addition of generating new payment transactions for queries") 534 call := func(request *services.Query) *services.Response { 535 require.NotNil(t, request.Query) 536 accountInfoQuery := request.Query.(*services.Query_CryptoGetInfo).CryptoGetInfo 537 538 require.Equal(t, accountInfoQuery.AccountID.String(), AccountID{Account: 5}._ToProtobuf().String()) 539 540 var payment services.TransactionBody 541 require.NotEmpty(t, accountInfoQuery.Header.Payment.BodyBytes) 542 err := protobuf.Unmarshal(accountInfoQuery.Header.Payment.BodyBytes, &payment) 543 require.NoError(t, err) 544 545 require.NotNil(t, payment.TransactionID) 546 require.Equal(t, payment.TransactionID.AccountID.String(), AccountID{Account: 1800}._ToProtobuf().String()) 547 require.NotNil(t, payment.NodeAccountID) 548 require.Equal(t, payment.NodeAccountID.String(), AccountID{Account: 3}._ToProtobuf().String()) 549 550 require.Equal(t, payment.Data, &services.TransactionBody_CryptoTransfer{ 551 CryptoTransfer: &services.CryptoTransferTransactionBody{ 552 Transfers: &services.TransferList{ 553 AccountAmounts: []*services.AccountAmount{ 554 { 555 AccountID: AccountID{Account: 3}._ToProtobuf(), 556 Amount: HbarFromTinybar(35).AsTinybar(), 557 }, 558 { 559 AccountID: AccountID{Account: 1800}._ToProtobuf(), 560 Amount: -HbarFromTinybar(35).AsTinybar(), 561 }, 562 }, 563 }, 564 }, 565 }) 566 567 key, _ := PrivateKeyFromStringEd25519(mockPrivateKey) 568 569 return &services.Response{ 570 Response: &services.Response_CryptoGetInfo{ 571 CryptoGetInfo: &services.CryptoGetInfoResponse{ 572 Header: &services.ResponseHeader{ 573 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 574 ResponseType: services.ResponseType_ANSWER_ONLY, 575 Cost: 35, 576 }, 577 AccountInfo: &services.CryptoGetInfoResponse_AccountInfo{ 578 AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}}, 579 ContractAccountID: "", 580 Deleted: false, 581 ProxyAccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}}, 582 ProxyReceived: 0, 583 Key: key._ToProtoKey(), 584 Balance: 0, 585 }, 586 }, 587 }, 588 } 589 } 590 591 costCall := func(request *services.Query) *services.Response { 592 require.NotNil(t, request.Query) 593 accountInfoQuery := request.Query.(*services.Query_CryptoGetInfo).CryptoGetInfo 594 595 require.Equal(t, accountInfoQuery.Header.ResponseType, services.ResponseType_COST_ANSWER) 596 597 require.Equal(t, accountInfoQuery.AccountID.String(), AccountID{Account: 5}._ToProtobuf().String()) 598 599 var payment services.TransactionBody 600 require.NotEmpty(t, accountInfoQuery.Header.Payment.BodyBytes) 601 err := protobuf.Unmarshal(accountInfoQuery.Header.Payment.BodyBytes, &payment) 602 require.NoError(t, err) 603 604 return &services.Response{ 605 Response: &services.Response_CryptoGetInfo{ 606 CryptoGetInfo: &services.CryptoGetInfoResponse{ 607 Header: &services.ResponseHeader{ 608 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 609 ResponseType: services.ResponseType_COST_ANSWER, 610 Cost: 35, 611 }, 612 }, 613 }, 614 } 615 } 616 617 responses := [][]interface{}{{ 618 costCall, call, 619 }} 620 621 client, server := NewMockClientAndServer(responses) 622 defer server.Close() 623 624 _, err := NewAccountInfoQuery(). 625 SetNodeAccountIDs([]AccountID{{Account: 3}}). 626 SetAccountID(AccountID{Account: 5}). 627 Execute(client) 628 require.NoError(t, err) 629 } 630 631 func TestUnitMockAccountInfoQueryNoNodeSet(t *testing.T) { 632 t.Skip("Skipping test as it is currently broken with the addition of generating new payment transactions for queries") 633 call := func(request *services.Query) *services.Response { 634 require.NotNil(t, request.Query) 635 accountInfoQuery := request.Query.(*services.Query_CryptoGetInfo).CryptoGetInfo 636 637 require.Equal(t, accountInfoQuery.AccountID.String(), AccountID{Account: 5}._ToProtobuf().String()) 638 639 var payment services.TransactionBody 640 require.NotEmpty(t, accountInfoQuery.Header.Payment.BodyBytes) 641 err := protobuf.Unmarshal(accountInfoQuery.Header.Payment.BodyBytes, &payment) 642 require.NoError(t, err) 643 644 require.NotNil(t, payment.TransactionID) 645 require.Equal(t, payment.TransactionID.AccountID.String(), AccountID{Account: 1800}._ToProtobuf().String()) 646 require.NotNil(t, payment.NodeAccountID) 647 require.Equal(t, payment.NodeAccountID.String(), AccountID{Account: 3}._ToProtobuf().String()) 648 649 require.Equal(t, payment.Data, &services.TransactionBody_CryptoTransfer{ 650 CryptoTransfer: &services.CryptoTransferTransactionBody{ 651 Transfers: &services.TransferList{ 652 AccountAmounts: []*services.AccountAmount{ 653 { 654 AccountID: AccountID{Account: 3}._ToProtobuf(), 655 Amount: HbarFromTinybar(35).AsTinybar(), 656 }, 657 { 658 AccountID: AccountID{Account: 1800}._ToProtobuf(), 659 Amount: -HbarFromTinybar(35).AsTinybar(), 660 }, 661 }, 662 }, 663 }, 664 }) 665 666 key, _ := PrivateKeyFromStringEd25519(mockPrivateKey) 667 668 return &services.Response{ 669 Response: &services.Response_CryptoGetInfo{ 670 CryptoGetInfo: &services.CryptoGetInfoResponse{ 671 Header: &services.ResponseHeader{ 672 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 673 ResponseType: services.ResponseType_ANSWER_ONLY, 674 Cost: 35, 675 }, 676 AccountInfo: &services.CryptoGetInfoResponse_AccountInfo{ 677 AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}}, 678 ContractAccountID: "", 679 Deleted: false, 680 ProxyAccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}}, 681 ProxyReceived: 0, 682 Key: key._ToProtoKey(), 683 Balance: 0, 684 }, 685 }, 686 }, 687 } 688 } 689 690 costCall := func(request *services.Query) *services.Response { 691 require.NotNil(t, request.Query) 692 accountInfoQuery := request.Query.(*services.Query_CryptoGetInfo).CryptoGetInfo 693 694 require.Equal(t, accountInfoQuery.Header.ResponseType, services.ResponseType_COST_ANSWER) 695 696 require.Equal(t, accountInfoQuery.AccountID.String(), AccountID{Account: 5}._ToProtobuf().String()) 697 698 var payment services.TransactionBody 699 require.NotEmpty(t, accountInfoQuery.Header.Payment.BodyBytes) 700 err := protobuf.Unmarshal(accountInfoQuery.Header.Payment.BodyBytes, &payment) 701 require.NoError(t, err) 702 703 return &services.Response{ 704 Response: &services.Response_CryptoGetInfo{ 705 CryptoGetInfo: &services.CryptoGetInfoResponse{ 706 Header: &services.ResponseHeader{ 707 NodeTransactionPrecheckCode: services.ResponseCodeEnum_OK, 708 ResponseType: services.ResponseType_COST_ANSWER, 709 Cost: 35, 710 }, 711 }, 712 }, 713 } 714 } 715 716 responses := [][]interface{}{{ 717 costCall, call, 718 }} 719 720 client, server := NewMockClientAndServer(responses) 721 defer server.Close() 722 723 _, err := NewAccountInfoQuery(). 724 SetAccountID(AccountID{Account: 5}). 725 Execute(client) 726 require.NoError(t, err) 727 } 728 729 func NewMockHandler(responses []interface{}) func(interface{}, context.Context, func(interface{}) error, grpc.UnaryServerInterceptor) (interface{}, error) { 730 index := 0 731 return func(_srv interface{}, _ctx context.Context, dec func(interface{}) error, _interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 732 if index >= len(responses) { 733 return nil, status.New(codes.Aborted, "No response found").Err() 734 } 735 response := responses[index] 736 index = index + 1 737 738 switch response := response.(type) { 739 case error: 740 return nil, response 741 case *services.TransactionResponse: 742 return response, nil 743 case *services.Response: 744 return response, nil 745 case *services.NodeAddress: 746 return response, nil 747 case func(request *services.Transaction) *services.TransactionResponse: 748 request := new(services.Transaction) 749 if err := dec(request); err != nil { 750 return nil, err 751 } 752 return response(request), nil 753 case func(request *services.Query) *services.Response: 754 request := new(services.Query) 755 if err := dec(request); err != nil { 756 return nil, err 757 } 758 return response(request), nil 759 case func(request *services.Query) *services.NodeAddress: 760 request := new(services.Query) 761 if err := dec(request); err != nil { 762 return nil, err 763 } 764 return response(request), nil 765 default: 766 return response, nil 767 } 768 } 769 } 770 771 func NewMockStreamHandler(responses []interface{}) func(interface{}, grpc.ServerStream) error { 772 return func(_ interface{}, stream grpc.ServerStream) error { 773 for _, resp := range responses { 774 err := stream.SendMsg(resp) 775 if err != nil { 776 return err 777 } 778 } 779 780 return nil 781 } 782 } 783 784 type MockServer struct { 785 listener net.Listener 786 server *grpc.Server 787 } 788 789 func NewMockServer(responses []interface{}) (server *MockServer) { 790 var err error 791 server = &MockServer{ 792 server: grpc.NewServer(), 793 } 794 handler := NewMockHandler(responses) 795 streamHandler := NewMockStreamHandler(responses) 796 797 server.server.RegisterService(NewServiceDescription(handler, &services.CryptoService_ServiceDesc), nil) 798 server.server.RegisterService(NewServiceDescription(handler, &services.FileService_ServiceDesc), nil) 799 server.server.RegisterService(NewServiceDescription(handler, &services.SmartContractService_ServiceDesc), nil) 800 server.server.RegisterService(NewServiceDescription(handler, &services.ConsensusService_ServiceDesc), nil) 801 server.server.RegisterService(NewServiceDescription(handler, &services.TokenService_ServiceDesc), nil) 802 server.server.RegisterService(NewServiceDescription(handler, &services.ScheduleService_ServiceDesc), nil) 803 server.server.RegisterService(NewServiceDescription(handler, &services.FreezeService_ServiceDesc), nil) 804 server.server.RegisterService(NewServiceDescription(handler, &services.NetworkService_ServiceDesc), nil) 805 server.server.RegisterService(NewServiceDescription(handler, &services.AddressBookService_ServiceDesc), nil) 806 server.server.RegisterService(NewMirrorServiceDescription(streamHandler, &mirror.NetworkService_ServiceDesc), nil) 807 808 server.listener, err = net.Listen("tcp", "localhost:0") 809 if err != nil { 810 panic(err) 811 } 812 813 go func() { 814 if err = server.server.Serve(server.listener); err != nil { 815 panic(err) 816 } 817 }() 818 819 return server 820 } 821 822 func (server *MockServer) Close() { 823 if server.server != nil { 824 server.server.GracefulStop() 825 } 826 } 827 828 func NewServiceDescription(handler func(interface{}, context.Context, func(interface{}) error, grpc.UnaryServerInterceptor) (interface{}, error), service *grpc.ServiceDesc) *grpc.ServiceDesc { 829 var methods []grpc.MethodDesc 830 for _, desc := range service.Methods { 831 methods = append(methods, grpc.MethodDesc{ 832 MethodName: desc.MethodName, 833 Handler: handler, 834 }) 835 } 836 837 return &grpc.ServiceDesc{ 838 ServiceName: service.ServiceName, 839 HandlerType: service.HandlerType, 840 Methods: methods, 841 Streams: []grpc.StreamDesc{}, 842 Metadata: service.Metadata, 843 } 844 } 845 846 func NewMirrorServiceDescription(handler func(interface{}, grpc.ServerStream) error, service *grpc.ServiceDesc) *grpc.ServiceDesc { 847 var streams []grpc.StreamDesc 848 for _, stream := range service.Streams { 849 streams = append(streams, grpc.StreamDesc{ 850 StreamName: stream.StreamName, 851 Handler: handler, 852 ServerStreams: stream.ServerStreams, 853 ClientStreams: stream.ClientStreams, 854 }) 855 } 856 857 return &grpc.ServiceDesc{ 858 ServiceName: service.ServiceName, 859 HandlerType: service.HandlerType, 860 Methods: []grpc.MethodDesc{}, 861 Streams: streams, 862 Metadata: service.Metadata, 863 } 864 }