Implement test of logged socket.io communication - WIP

This commit is contained in:
Martin Boehm 2018-05-04 12:37:11 +02:00
parent ecd475f728
commit 9b061850f2
2 changed files with 145 additions and 29 deletions

View File

@ -466,18 +466,18 @@ func unmarshalGetBlockHeader(params []byte) (height uint32, hash string, err err
type resultGetBlockHeader struct { type resultGetBlockHeader struct {
Result struct { Result struct {
Hash string `json:"hash"` Hash string `json:"hash"`
Version int `json:"version"` Version int `json:"version"`
Confirmations int `json:"confirmations"` Confirmations int `json:"confirmations"`
Height int `json:"height"` Height int `json:"height"`
ChainWork string `json:"chainWork"` ChainWork string `json:"chainWork"`
NextHash string `json:"nextHash"` NextHash string `json:"nextHash"`
MerkleRoot string `json:"merkleRoot"` MerkleRoot string `json:"merkleRoot"`
Time int `json:"time"` Time int `json:"time"`
MedianTime int `json:"medianTime"` MedianTime int `json:"medianTime"`
Nonce int `json:"nonce"` Nonce int `json:"nonce"`
Bits string `json:"bits"` Bits string `json:"bits"`
Difficulty int `json:"difficulty"` Difficulty float64 `json:"difficulty"`
} `json:"result"` } `json:"result"`
} }

View File

@ -18,8 +18,8 @@ import (
var ( var (
// verifier functionality // verifier functionality
verifylog = flag.String("verifylog", "", "path to logfile containing socket.io requests/responses") verifylog = flag.String("verifylog", "/Users/mxb2/Downloads/messageLogBtc.log", "path to logfile containing socket.io requests/responses")
wsurl = flag.String("wsurl", "", "URL of socket.io interface to verify") wsurl = flag.String("wsurl", "wss://blockbook-dev:8336", "URL of socket.io interface to verify")
) )
type verifyStats struct { type verifyStats struct {
@ -50,23 +50,134 @@ func getStat(m string, stats map[string]*verifyStats) *verifyStats {
return s return s
} }
func verifyGetInfo(t *testing.T, id int, lrs *logRequestResponse, bbRequest map[string]json.RawMessage, bbResponseS string, stat *verifyStats) { func unmarshalResponses(t *testing.T, id int, lrs *logRequestResponse, bbResStr string, bbResponse interface{}, logResponse interface{}) error {
bbResponse := resultGetInfo{} err := json.Unmarshal([]byte(bbResStr), bbResponse)
err := json.Unmarshal([]byte(bbResponseS), &bbResponse)
if err != nil { if err != nil {
t.Log(id, ": error unmarshal BB request ", err) t.Log(id, ": error unmarshal BB request ", err)
return return err
} }
logResponse := resultGetInfo{} err = json.Unmarshal([]byte(lrs.Response), logResponse)
err = json.Unmarshal([]byte(lrs.Response), &logResponse)
if err != nil { if err != nil {
t.Log(id, ": error unmarshal log request ", err) t.Log(id, ": error unmarshal log request ", err)
return err
}
return nil
}
func verifyGetAddressHistory(t *testing.T, id int, lrs *logRequestResponse, bbResStr string, stat *verifyStats, ws *gosocketio.Client, bbRequest map[string]json.RawMessage) {
type reqParamsData struct {
Start int `json:"start"`
End int `json:"end"`
QueryMempoolOnly bool `json:"queryMempoolOnly"`
From int `json:"from"`
To int `json:"to"`
}
bbResponse := resultGetAddressHistory{}
logResponse := resultGetAddressHistory{}
if err := unmarshalResponses(t, id, lrs, bbResStr, &bbResponse, &logResponse); err != nil {
return
}
// parse request
addr, rr, err := unmarshalGetAddressRequest(bbRequest["params"])
if err != nil {
t.Log(id, ": getAddressHistory error unmarshal BB request ", err)
return
}
if !rr.QueryMempoolOnly {
if (logResponse.Result.TotalCount != bbResponse.Result.TotalCount) ||
len(logResponse.Result.Items) != len(bbResponse.Result.Items) {
t.Log("getAddressHistory", id, "mismatch bb:", bbResponse.Result.TotalCount, len(bbResponse.Result.Items),
"log:", logResponse.Result.TotalCount, len(logResponse.Result.Items))
return
}
if logResponse.Result.TotalCount > 0 {
for i, logItem := range logResponse.Result.Items {
bbItem := bbResponse.Result.Items[i]
if logItem.Tx.Hash != bbItem.Tx.Hash || logItem.Tx.Hex != bbItem.Tx.Hex {
t.Log("getAddressHistory", id, "mismatch in tx", i, "bb:", bbItem.Tx.Hash,
"log:", logItem.Tx.Hash)
// if multiple addresses are specified, BlockBook returns transactions in different order
// which causes problems in paged responses
// we have to get all transactions from blockbook and check that they are in the logged response
rr.From = 0
rr.To = 100000000
rq := map[string]interface{}{
"method": "getAddressHistory",
"params": []interface{}{
addr,
rr,
},
}
rrq, err := json.Marshal(rq)
if err != nil {
t.Log(id, ", getAddressHistory: rq marshall error ", err)
return
}
res, err := ws.Ack("message", json.RawMessage(rrq), time.Second*30)
if err != nil {
t.Log(id, ", getAddressHistory: ws.Ack error ", err)
return
}
bbFullResponse := resultGetAddressHistory{}
t.Log(id, ": bbResponse", bbResponse.Result.TotalCount, "bbFullResponse", bbFullResponse.Result.TotalCount)
t.Log(string(rrq))
err = json.Unmarshal([]byte(res), &bbFullResponse)
if err != nil {
t.Log(id, ": getAddressHistory error unmarshal BB response ", err)
return
}
return
}
}
}
}
stat.SuccessCount++
}
func verifyGetInfo(t *testing.T, id int, lrs *logRequestResponse, bbResStr string, stat *verifyStats) {
bbResponse := resultGetInfo{}
logResponse := resultGetInfo{}
if err := unmarshalResponses(t, id, lrs, bbResStr, &bbResponse, &logResponse); err != nil {
return return
} }
if logResponse.Result.Blocks <= bbResponse.Result.Blocks && if logResponse.Result.Blocks <= bbResponse.Result.Blocks &&
logResponse.Result.Testnet == bbResponse.Result.Testnet && logResponse.Result.Testnet == bbResponse.Result.Testnet &&
logResponse.Result.Network == bbResponse.Result.Network { logResponse.Result.Network == bbResponse.Result.Network {
stat.SuccessCount++ stat.SuccessCount++
} else {
t.Log("getInfo", id, "mismatch bb:", bbResponse.Result.Blocks, bbResponse.Result.Testnet, bbResponse.Result.Network,
"log:", logResponse.Result.Blocks, logResponse.Result.Testnet, logResponse.Result.Network)
}
}
func verifyGetBlockHeader(t *testing.T, id int, lrs *logRequestResponse, bbResStr string, stat *verifyStats) {
bbResponse := resultGetBlockHeader{}
logResponse := resultGetBlockHeader{}
if err := unmarshalResponses(t, id, lrs, bbResStr, &bbResponse, &logResponse); err != nil {
return
}
if logResponse.Result.Hash == bbResponse.Result.Hash {
stat.SuccessCount++
} else {
t.Log("getBlockHeader", id, "mismatch bb:", bbResponse.Result.Hash,
"log:", logResponse.Result.Hash)
}
}
func verifyEstimateSmartFee(t *testing.T, id int, lrs *logRequestResponse, bbResStr string, stat *verifyStats) {
bbResponse := resultEstimateSmartFee{}
logResponse := resultEstimateSmartFee{}
if err := unmarshalResponses(t, id, lrs, bbResStr, &bbResponse, &logResponse); err != nil {
return
}
// it is not possible to compare fee directly, it changes over time,
// verify that the BB fee is in a reasonable range
if bbResponse.Result > 0 && bbResponse.Result < 1e-3 {
stat.SuccessCount++
} else {
t.Log("estimateSmartFee", id, "mismatch bb:", bbResponse.Result,
"log:", logResponse.Result)
} }
} }
@ -91,25 +202,27 @@ func verifyMessage(t *testing.T, ws *gosocketio.Client, id int, lrs *logRequestR
return return
} }
ts := time.Since(start).Nanoseconds() ts := time.Since(start).Nanoseconds()
t.Log(id, ",", method, ": response ", res) // t.Log(id, ",", method, ": response ", res)
stat := getStat(method, stats) stat := getStat(method, stats)
stat.Count++ stat.Count++
stat.TotalLogNs += lrs.LogElapsedTime stat.TotalLogNs += lrs.LogElapsedTime
stat.TotalBlockbookNs += ts stat.TotalBlockbookNs += ts
switch method { switch method {
case "getAddressTxids": // case "getAddressTxids":
case "getAddressHistory": case "getAddressHistory":
verifyGetAddressHistory(t, id, lrs, res, stat, ws, req)
case "getBlockHeader": case "getBlockHeader":
verifyGetBlockHeader(t, id, lrs, res, stat)
case "getDetailedTransaction": case "getDetailedTransaction":
case "getInfo": case "getInfo":
verifyGetInfo(t, id, lrs, req, res, stat) verifyGetInfo(t, id, lrs, res, stat)
case "estimateSmartFee": case "estimateSmartFee":
case "estimateFee": verifyEstimateSmartFee(t, id, lrs, res, stat)
case "sendTransaction": // case "estimateFee":
case "getMempoolEntry": // case "sendTransaction":
break // case "getMempoolEntry":
default: default:
t.Log(id, ",", method, ": unknown method", method) t.Log(id, ",", method, ": unknown/unverified method", method)
} }
} }
@ -177,10 +290,13 @@ func Test_VerifyLog(t *testing.T) {
} }
failures := 0 failures := 0
sort.Strings(keys) sort.Strings(keys)
t.Log("Processed", line, "lines")
for _, k := range keys { for _, k := range keys {
s := stats[k] s := stats[k]
failures += s.Count - s.SuccessCount failures += s.Count - s.SuccessCount
t.Log("Method:", k, "\tCount:", s.Count, "\tSuccess:", s.SuccessCount, "\tTime log:", s.TotalLogNs, "\tTime BB:", s.TotalBlockbookNs) t.Log("Method:", k, "\tCount:", s.Count, "\tSuccess:", s.SuccessCount,
"\tTime log:", s.TotalLogNs, "\tTime BB:", s.TotalBlockbookNs,
"\tTime BB/log", float64(s.TotalBlockbookNs)/float64(s.TotalLogNs))
} }
if failures != 0 { if failures != 0 {
t.Error("Number of failures:", failures) t.Error("Number of failures:", failures)