Cover exposed methods (library.go) with tests. Fixes #57
This commit is contained in:
parent
1f6e59d160
commit
e87ad0705f
|
@ -117,28 +117,6 @@ func Logout() *C.char {
|
|||
return C.CString(string(outBytes))
|
||||
}
|
||||
|
||||
//export UnlockAccount
|
||||
func UnlockAccount(address, password *C.char, seconds int) *C.char {
|
||||
|
||||
// This is equivalent to unlocking an account from the command line,
|
||||
// just modified to unlock the account for the currently running geth node
|
||||
// based on the provided arguments
|
||||
err := geth.UnlockAccount(C.GoString(address), C.GoString(password), seconds)
|
||||
|
||||
errString := ""
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
errString = err.Error()
|
||||
}
|
||||
|
||||
out := geth.JSONError{
|
||||
Error: errString,
|
||||
}
|
||||
outBytes, _ := json.Marshal(&out)
|
||||
|
||||
return C.CString(string(outBytes))
|
||||
}
|
||||
|
||||
//export CompleteTransaction
|
||||
func CompleteTransaction(id, password *C.char) *C.char {
|
||||
txHash, err := geth.CompleteTransaction(C.GoString(id), C.GoString(password))
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -10,7 +11,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/les/status"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/status-im/status-go/geth"
|
||||
|
@ -23,6 +26,7 @@ const (
|
|||
testAddressPassword = "asdf"
|
||||
newAccountPassword = "badpassword"
|
||||
testAddress1 = "0xf82da7547534045b4e00442bc89e16186cf8c272"
|
||||
testStatusJsFile = "../../jail/testdata/status.js"
|
||||
)
|
||||
|
||||
func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||
|
@ -32,14 +36,46 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
|||
name string
|
||||
fn func(t *testing.T) bool
|
||||
}{
|
||||
{
|
||||
"create main and child accounts",
|
||||
testCreateChildAccount,
|
||||
},
|
||||
{
|
||||
"recover account",
|
||||
testRecoverAccount,
|
||||
},
|
||||
{
|
||||
"account select/login",
|
||||
testAccountSelect,
|
||||
},
|
||||
{
|
||||
"account logout",
|
||||
testAccountLogout,
|
||||
},
|
||||
{
|
||||
"complete single queued transaction",
|
||||
testCompleteTransaction,
|
||||
},
|
||||
{
|
||||
"test complete multiple queued transactions",
|
||||
testCompleteMultipleQueuedTransactions,
|
||||
},
|
||||
{
|
||||
"discard single queued transaction",
|
||||
testDiscardTransaction,
|
||||
},
|
||||
{
|
||||
"test discard multiple queued transactions",
|
||||
testDiscardMultipleQueuedTransactions,
|
||||
},
|
||||
{
|
||||
"test jail initialization",
|
||||
testJailInit,
|
||||
},
|
||||
{
|
||||
"test jailed calls",
|
||||
testJailFunctionCall,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -51,6 +87,468 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
|||
done <- struct{}{}
|
||||
}
|
||||
|
||||
func testCreateChildAccount(t *testing.T) bool {
|
||||
geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests)
|
||||
|
||||
accountManager, err := geth.GetNodeManager().AccountManager()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
// create an account
|
||||
createAccountResponse := geth.AccountInfo{}
|
||||
rawResponse := CreateAccount(C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createAccountResponse); err != nil {
|
||||
t.Errorf("cannot decode CreateAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if createAccountResponse.Error != "" {
|
||||
t.Errorf("could not create account: %s", err)
|
||||
return false
|
||||
}
|
||||
address, pubKey, mnemonic := createAccountResponse.Address, createAccountResponse.PubKey, createAccountResponse.Mnemonic
|
||||
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||
|
||||
account, err := utils.MakeAddress(accountManager, address)
|
||||
if err != nil {
|
||||
t.Errorf("can not get account from address: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
|
||||
account, key, err := accountManager.AccountDecryptedKey(account, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if key.ExtendedKey == nil {
|
||||
t.Error("CKD#2 has not been generated for new account")
|
||||
return false
|
||||
}
|
||||
|
||||
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
|
||||
createSubAccountResponse := geth.AccountInfo{}
|
||||
rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil {
|
||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if createSubAccountResponse.Error != geth.ErrNoAccountSelected.Error() {
|
||||
t.Errorf("expected error is not returned (tried to create sub-account w/o login): %v", createSubAccountResponse.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
err = geth.SelectAccount(address, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: could not select account: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// try to create sub-account with wrong password
|
||||
createSubAccountResponse = geth.AccountInfo{}
|
||||
rawResponse = CreateChildAccount(C.CString(""), C.CString("wrong password"))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil {
|
||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if createSubAccountResponse.Error != "cannot retreive a valid key for a given account: could not decrypt key with given passphrase" {
|
||||
t.Errorf("expected error is not returned (tried to create sub-account with wrong password): %v", createSubAccountResponse.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
// create sub-account (from implicit parent)
|
||||
createSubAccountResponse1 := geth.AccountInfo{}
|
||||
rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse1); err != nil {
|
||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if createSubAccountResponse1.Error != "" {
|
||||
t.Errorf("cannot create sub-account: %v", createSubAccountResponse1.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
// make sure that sub-account index automatically progresses
|
||||
createSubAccountResponse2 := geth.AccountInfo{}
|
||||
rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse2); err != nil {
|
||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if createSubAccountResponse2.Error != "" {
|
||||
t.Errorf("cannot create sub-account: %v", createSubAccountResponse2.Error)
|
||||
}
|
||||
|
||||
if createSubAccountResponse1.Address == createSubAccountResponse2.Address || createSubAccountResponse1.PubKey == createSubAccountResponse2.PubKey {
|
||||
t.Error("sub-account index auto-increament failed")
|
||||
return false
|
||||
}
|
||||
|
||||
// create sub-account (from explicit parent)
|
||||
createSubAccountResponse3 := geth.AccountInfo{}
|
||||
rawResponse = CreateChildAccount(C.CString(createSubAccountResponse2.Address), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse3); err != nil {
|
||||
t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if createSubAccountResponse3.Error != "" {
|
||||
t.Errorf("cannot create sub-account: %v", createSubAccountResponse3.Error)
|
||||
}
|
||||
|
||||
subAccount1, subAccount2, subAccount3 := createSubAccountResponse1.Address, createSubAccountResponse2.Address, createSubAccountResponse3.Address
|
||||
subPubKey1, subPubKey2, subPubKey3 := createSubAccountResponse1.PubKey, createSubAccountResponse2.PubKey, createSubAccountResponse3.PubKey
|
||||
|
||||
if subAccount1 == subAccount3 || subPubKey1 == subPubKey3 || subAccount2 == subAccount3 || subPubKey2 == subPubKey3 {
|
||||
t.Error("sub-account index auto-increament failed")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testRecoverAccount(t *testing.T) bool {
|
||||
accountManager, _ := geth.GetNodeManager().AccountManager()
|
||||
|
||||
// create an account
|
||||
address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return false
|
||||
}
|
||||
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||
|
||||
// try recovering using password + mnemonic
|
||||
recoverAccountResponse := geth.AccountInfo{}
|
||||
rawResponse := RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if recoverAccountResponse.Error != "" {
|
||||
t.Errorf("recover account failed: %v", recoverAccountResponse.Error)
|
||||
return false
|
||||
}
|
||||
addressCheck, pubKeyCheck := recoverAccountResponse.Address, recoverAccountResponse.PubKey
|
||||
if address != addressCheck || pubKey != pubKeyCheck {
|
||||
t.Error("recover account details failed to pull the correct details")
|
||||
}
|
||||
|
||||
// now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device
|
||||
account, err := utils.MakeAddress(accountManager, address)
|
||||
if err != nil {
|
||||
t.Errorf("can not get account from address: %v", err)
|
||||
}
|
||||
|
||||
account, key, err := accountManager.AccountDecryptedKey(account, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||
return false
|
||||
}
|
||||
extChild2String := key.ExtendedKey.String()
|
||||
|
||||
if err := accountManager.DeleteAccount(account, newAccountPassword); err != nil {
|
||||
t.Errorf("cannot remove account: %v", err)
|
||||
}
|
||||
|
||||
recoverAccountResponse = geth.AccountInfo{}
|
||||
rawResponse = RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if recoverAccountResponse.Error != "" {
|
||||
t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error)
|
||||
return false
|
||||
}
|
||||
addressCheck, pubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey
|
||||
if address != addressCheck || pubKey != pubKeyCheck {
|
||||
t.Error("recover account details failed to pull the correct details (for non-cached account)")
|
||||
}
|
||||
|
||||
// make sure that extended key exists and is imported ok too
|
||||
account, key, err = accountManager.AccountDecryptedKey(account, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("can not obtain decrypted account key: %v", err)
|
||||
return false
|
||||
}
|
||||
if extChild2String != key.ExtendedKey.String() {
|
||||
t.Errorf("CKD#2 key mismatch, expected: %s, got: %s", extChild2String, key.ExtendedKey.String())
|
||||
}
|
||||
|
||||
// make sure that calling import several times, just returns from cache (no error is expected)
|
||||
recoverAccountResponse = geth.AccountInfo{}
|
||||
rawResponse = RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if recoverAccountResponse.Error != "" {
|
||||
t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error)
|
||||
return false
|
||||
}
|
||||
addressCheck, pubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey
|
||||
if address != addressCheck || pubKey != pubKeyCheck {
|
||||
t.Error("recover account details failed to pull the correct details (for non-cached account)")
|
||||
}
|
||||
|
||||
// time to login with recovered data
|
||||
whisperService, err := geth.GetNodeManager().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
|
||||
// make sure that identity is not (yet injected)
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
err = geth.SelectAccount(addressCheck, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: could not select account: %v", err)
|
||||
return false
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testAccountSelect(t *testing.T) bool {
|
||||
// test to see if the account was injected in whisper
|
||||
whisperService, err := geth.GetNodeManager().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
}
|
||||
|
||||
// create an account
|
||||
address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return false
|
||||
}
|
||||
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||
|
||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Error("Test failed: could not create account")
|
||||
return false
|
||||
}
|
||||
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||
|
||||
// make sure that identity is not (yet injected)
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
|
||||
// try selecting with wrong password
|
||||
loginResponse := geth.JSONError{}
|
||||
rawResponse := Login(C.CString(address1), C.CString("wrongPassword"))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if loginResponse.Error == "" {
|
||||
t.Error("select account is expected to throw error: wrong password used")
|
||||
return false
|
||||
}
|
||||
|
||||
loginResponse = geth.JSONError{}
|
||||
rawResponse = Login(C.CString(address1), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if loginResponse.Error != "" {
|
||||
t.Errorf("Test failed: could not select account: %v", err)
|
||||
return false
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
|
||||
// select another account, make sure that previous account is wiped out from Whisper cache
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
||||
t.Error("identity already present in whisper")
|
||||
}
|
||||
|
||||
loginResponse = geth.JSONError{}
|
||||
rawResponse = Login(C.CString(address2), C.CString(newAccountPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if loginResponse.Error != "" {
|
||||
t.Errorf("Test failed: could not select account: %v", loginResponse.Error)
|
||||
return false
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) {
|
||||
t.Errorf("identity not injected into whisper: %v", err)
|
||||
}
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
t.Error("identity should be removed, but it is still present in whisper")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testAccountLogout(t *testing.T) bool {
|
||||
whisperService, err := geth.GetNodeManager().WhisperService()
|
||||
if err != nil {
|
||||
t.Errorf("whisper service not running: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// create an account
|
||||
address, pubKey, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("could not create account: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// make sure that identity doesn't exist (yet) in Whisper
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
||||
t.Error("identity already present in whisper")
|
||||
return false
|
||||
}
|
||||
|
||||
// select/login
|
||||
err = geth.SelectAccount(address, newAccountPassword)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: could not select account: %v", err)
|
||||
return false
|
||||
}
|
||||
if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
||||
t.Error("identity not injected into whisper")
|
||||
return false
|
||||
}
|
||||
|
||||
logoutResponse := geth.JSONError{}
|
||||
rawResponse := Logout()
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &logoutResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
}
|
||||
|
||||
if logoutResponse.Error != "" {
|
||||
t.Errorf("cannot logout: %v", logoutResponse.Error)
|
||||
return false
|
||||
}
|
||||
|
||||
// now, logout and check if identity is removed indeed
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) {
|
||||
t.Error("identity not cleared from whisper")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testCompleteTransaction(t *testing.T) bool {
|
||||
// obtain reference to status backend
|
||||
lightEthereum, err := geth.GetNodeManager().LightEthereumService()
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: LES service is not running: %v", err)
|
||||
return false
|
||||
}
|
||||
backend := lightEthereum.StatusBackend
|
||||
|
||||
// reset queue
|
||||
backend.TransactionQueue().Reset()
|
||||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
queuedTxCompleted := make(chan struct{}, 1)
|
||||
abortPanic := make(chan struct{}, 1)
|
||||
geth.PanicAfter(10*time.Second, abortPanic, "testCompleteTransaction")
|
||||
|
||||
// replace transaction notification handler
|
||||
var txHash = ""
|
||||
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
||||
var envelope geth.GethEvent
|
||||
if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil {
|
||||
t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
|
||||
return
|
||||
}
|
||||
if envelope.Type == geth.EventTransactionQueued {
|
||||
event := envelope.Event.(map[string]interface{})
|
||||
t.Logf("transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string))
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
completeTxResponse := geth.CompleteTransactionResult{}
|
||||
rawResponse := CompleteTransaction(C.CString(event["id"].(string)), C.CString(testAddressPassword))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &completeTxResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
}
|
||||
|
||||
if completeTxResponse.Error != "" {
|
||||
t.Errorf("cannot complete queued transation[%v]: %v", event["id"], completeTxResponse.Error)
|
||||
}
|
||||
|
||||
txHash = completeTxResponse.Hash
|
||||
|
||||
t.Logf("transaction complete: https://testnet.etherscan.io/tx/%s", txHash)
|
||||
abortPanic <- struct{}{} // so that timeout is aborted
|
||||
queuedTxCompleted <- struct{}{}
|
||||
}
|
||||
})
|
||||
|
||||
// this call blocks, up until Complete Transaction is called
|
||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||
From: geth.FromAddress(testAddress),
|
||||
To: geth.ToAddress(testAddress1),
|
||||
Value: rpc.NewHexNumber(big.NewInt(1000000000000)),
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: cannot send transaction: %v", err)
|
||||
}
|
||||
|
||||
<-queuedTxCompleted // make sure that complete transaction handler completes its magic, before we proceed
|
||||
|
||||
if txHash != txHashCheck.Hex() {
|
||||
t.Errorf("Transaction hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck.Hex(), txHash)
|
||||
return false
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(txHashCheck, common.Hash{}) {
|
||||
t.Error("Test failed: transaction was never queued or completed")
|
||||
return false
|
||||
}
|
||||
|
||||
if backend.TransactionQueue().Count() != 0 {
|
||||
t.Error("tx queue must be empty at this point")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
|
||||
// obtain reference to status backend
|
||||
lightEthereum, err := geth.GetNodeManager().LightEthereumService()
|
||||
|
@ -180,6 +678,120 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func testDiscardTransaction(t *testing.T) bool {
|
||||
// obtain reference to status backend
|
||||
lightEthereum, err := geth.GetNodeManager().LightEthereumService()
|
||||
if err != nil {
|
||||
t.Errorf("Test failed: LES service is not running: %v", err)
|
||||
return false
|
||||
}
|
||||
backend := lightEthereum.StatusBackend
|
||||
|
||||
// reset queue
|
||||
backend.TransactionQueue().Reset()
|
||||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
completeQueuedTransaction := make(chan struct{}, 1)
|
||||
geth.PanicAfter(20*time.Second, completeQueuedTransaction, "TestDiscardQueuedTransactions")
|
||||
|
||||
// replace transaction notification handler
|
||||
var txId string
|
||||
txFailedEventCalled := false
|
||||
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
||||
var envelope geth.GethEvent
|
||||
if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil {
|
||||
t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
|
||||
return
|
||||
}
|
||||
if envelope.Type == geth.EventTransactionQueued {
|
||||
event := envelope.Event.(map[string]interface{})
|
||||
txId = event["id"].(string)
|
||||
t.Logf("transaction queued (will be discarded soon): {id: %s}\n", txId)
|
||||
|
||||
if !backend.TransactionQueue().Has(status.QueuedTxId(txId)) {
|
||||
t.Errorf("txqueue should still have test tx: %s", txId)
|
||||
return
|
||||
}
|
||||
|
||||
// discard
|
||||
discardResponse := geth.DiscardTransactionResult{}
|
||||
rawResponse := DiscardTransaction(C.CString(txId))
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &discardResponse); err != nil {
|
||||
t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err)
|
||||
}
|
||||
|
||||
if discardResponse.Error != "" {
|
||||
t.Errorf("cannot discard tx: %v", discardResponse.Error)
|
||||
return
|
||||
}
|
||||
|
||||
// try completing discarded transaction
|
||||
_, err = geth.CompleteTransaction(txId, testAddressPassword)
|
||||
if err.Error() != "transaction hash not found" {
|
||||
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
||||
if backend.TransactionQueue().Has(status.QueuedTxId(txId)) {
|
||||
t.Errorf("txqueue should not have test tx at this point (it should be discarded): %s", txId)
|
||||
return
|
||||
}
|
||||
|
||||
completeQueuedTransaction <- struct{}{} // so that timeout is aborted
|
||||
}
|
||||
|
||||
if envelope.Type == geth.EventTransactionFailed {
|
||||
event := envelope.Event.(map[string]interface{})
|
||||
t.Logf("transaction return event received: {id: %s}\n", event["id"].(string))
|
||||
|
||||
receivedErrMessage := event["error_message"].(string)
|
||||
expectedErrMessage := status.ErrQueuedTxDiscarded.Error()
|
||||
if receivedErrMessage != expectedErrMessage {
|
||||
t.Errorf("unexpected error message received: got %v", receivedErrMessage)
|
||||
return
|
||||
}
|
||||
|
||||
receivedErrCode := event["error_code"].(string)
|
||||
if receivedErrCode != geth.SendTransactionDiscardedErrorCode {
|
||||
t.Errorf("unexpected error code received: got %v", receivedErrCode)
|
||||
return
|
||||
}
|
||||
|
||||
txFailedEventCalled = true
|
||||
}
|
||||
})
|
||||
|
||||
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
||||
txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{
|
||||
From: geth.FromAddress(testAddress),
|
||||
To: geth.ToAddress(testAddress1),
|
||||
Value: rpc.NewHexNumber(big.NewInt(1000000000000)),
|
||||
})
|
||||
if err != status.ErrQueuedTxDiscarded {
|
||||
t.Errorf("expected error not thrown: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(txHashCheck, common.Hash{}) {
|
||||
t.Error("transaction returned hash, while it shouldn't")
|
||||
return false
|
||||
}
|
||||
|
||||
if backend.TransactionQueue().Count() != 0 {
|
||||
t.Error("tx queue must be empty at this point")
|
||||
return false
|
||||
}
|
||||
|
||||
if !txFailedEventCalled {
|
||||
t.Error("expected tx failure signal is not received")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
||||
// obtain reference to status backend
|
||||
lightEthereum, err := geth.GetNodeManager().LightEthereumService()
|
||||
|
@ -343,6 +955,67 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func testJailInit(t *testing.T) bool {
|
||||
initCode := `
|
||||
var _status_catalog = {
|
||||
foo: 'bar'
|
||||
};
|
||||
`
|
||||
InitJail(C.CString(initCode))
|
||||
|
||||
extraCode := `
|
||||
var extraFunc = function (x) {
|
||||
return x * x;
|
||||
};
|
||||
`
|
||||
rawResponse := Parse(C.CString("CHAT_ID_INIT_TEST"), C.CString(extraCode))
|
||||
parsedResponse := C.GoString(rawResponse)
|
||||
|
||||
expectedResponse := `{"result": {"foo":"bar"}}`
|
||||
|
||||
if !reflect.DeepEqual(expectedResponse, parsedResponse) {
|
||||
t.Error("expected output not returned from jail.Parse()")
|
||||
return false
|
||||
}
|
||||
|
||||
t.Logf("jail inited and parsed: %s", parsedResponse)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func testJailFunctionCall(t *testing.T) bool {
|
||||
InitJail(C.CString(""))
|
||||
|
||||
// load Status JS and add test command to it
|
||||
statusJS := geth.LoadFromFile(testStatusJsFile) + `;
|
||||
_status_catalog.commands["testCommand"] = function (params) {
|
||||
return params.val * params.val;
|
||||
};`
|
||||
Parse(C.CString("CHAT_ID_CALL_TEST"), C.CString(statusJS))
|
||||
|
||||
// call with wrong chat id
|
||||
rawResponse := Call(C.CString("CHAT_IDNON_EXISTENT"), C.CString(""), C.CString(""))
|
||||
parsedResponse := C.GoString(rawResponse)
|
||||
expectedError := `{"error":"Cell[CHAT_IDNON_EXISTENT] doesn't exist."}`
|
||||
if parsedResponse != expectedError {
|
||||
t.Errorf("expected error is not returned: expected %s, got %s", expectedError, parsedResponse)
|
||||
return false
|
||||
}
|
||||
|
||||
// call extraFunc()
|
||||
rawResponse = Call(C.CString("CHAT_ID_CALL_TEST"), C.CString(`["commands", "testCommand"]`), C.CString(`{"val": 12}`))
|
||||
parsedResponse = C.GoString(rawResponse)
|
||||
expectedResponse := `{"result": 144}`
|
||||
if parsedResponse != expectedResponse {
|
||||
t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, parsedResponse)
|
||||
return false
|
||||
}
|
||||
|
||||
t.Logf("jailed method called: %s", parsedResponse)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func startTestNode(t *testing.T) <-chan struct{} {
|
||||
syncRequired := false
|
||||
if _, err := os.Stat(filepath.Join(testDataDir, "testnet")); os.IsNotExist(err) {
|
||||
|
@ -360,6 +1033,21 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
|||
if envelope.Type == geth.EventTransactionQueued {
|
||||
}
|
||||
if envelope.Type == geth.EventNodeStarted {
|
||||
// manually add static nodes (LES auto-discovery is not stable yet)
|
||||
configFile, err := ioutil.ReadFile(filepath.Join("../../data", "static-nodes.json"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var enodes []string
|
||||
if err = json.Unmarshal(configFile, &enodes); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, enode := range enodes {
|
||||
AddPeer(C.CString(enode))
|
||||
}
|
||||
|
||||
// sync
|
||||
if syncRequired {
|
||||
t.Logf("Sync is required, it will take %d seconds", testNodeSyncSeconds)
|
||||
time.Sleep(testNodeSyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done
|
||||
|
@ -372,6 +1060,7 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
|||
}
|
||||
})
|
||||
|
||||
go func() {
|
||||
response := StartNode(C.CString(testDataDir))
|
||||
err := geth.JSONError{}
|
||||
|
||||
|
@ -379,6 +1068,7 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
|||
if err.Error != "" {
|
||||
t.Error("cannot start node")
|
||||
}
|
||||
}()
|
||||
|
||||
return waitForNodeStart
|
||||
}
|
||||
|
|
|
@ -2,15 +2,12 @@ package geth_test
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/status-im/status-go/geth"
|
||||
)
|
||||
|
||||
|
@ -145,7 +142,7 @@ func TestCreateChildAccount(t *testing.T) {
|
|||
t.Errorf("could not create account: %v", err)
|
||||
return
|
||||
}
|
||||
glog.V(logger.Info).Infof("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||
|
||||
account, err := utils.MakeAddress(accountManager, address)
|
||||
if err != nil {
|
||||
|
@ -228,7 +225,7 @@ func TestRecoverAccount(t *testing.T) {
|
|||
t.Errorf("could not create account: %v", err)
|
||||
return
|
||||
}
|
||||
glog.V(logger.Info).Infof("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
||||
|
||||
// try recovering using password + mnemonic
|
||||
addressCheck, pubKeyCheck, err := geth.RecoverAccount(newAccountPassword, mnemonic)
|
||||
|
@ -326,15 +323,14 @@ func TestAccountSelect(t *testing.T) {
|
|||
t.Errorf("could not create account: %v", err)
|
||||
return
|
||||
}
|
||||
glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||
|
||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Error("Test failed: could not create account")
|
||||
return
|
||||
}
|
||||
glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||
|
||||
// make sure that identity is not (yet injected)
|
||||
if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) {
|
||||
|
|
|
@ -45,7 +45,6 @@ func TestMain(m *testing.M) {
|
|||
err := geth.PrepareTestNode()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
|
||||
<-signalRecieved // block and wait for either panic or successful signal
|
||||
|
|
|
@ -7,8 +7,6 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/whisper"
|
||||
"github.com/status-im/status-go/geth"
|
||||
)
|
||||
|
@ -43,7 +41,7 @@ func TestWhisperMessaging(t *testing.T) {
|
|||
t.Error("Test failed: could not create account")
|
||||
return
|
||||
}
|
||||
glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
||||
|
||||
address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword)
|
||||
if err != nil {
|
||||
|
@ -51,7 +49,7 @@ func TestWhisperMessaging(t *testing.T) {
|
|||
t.Error("Test failed: could not create account")
|
||||
return
|
||||
}
|
||||
glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
||||
|
||||
// start watchers
|
||||
var receivedMessages = map[string]bool{
|
||||
|
@ -65,7 +63,7 @@ func TestWhisperMessaging(t *testing.T) {
|
|||
//From: crypto.ToECDSAPub(common.FromHex(pubKey1)),
|
||||
//To: crypto.ToECDSAPub(common.FromHex(pubKey2)),
|
||||
Fn: func(msg *whisper.Message) {
|
||||
//glog.V(logger.Info).Infof("Whisper message received: %s", msg.Payload)
|
||||
//t.Logf("Whisper message received: %s", msg.Payload)
|
||||
receivedMessages[string(msg.Payload)] = true
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue