Add RpcRawCommand and export ReadResultCommand.

Add new RpcRawCommand to get []byte represtation of reply instead of
btcjson.Result.

Export ReadResultCommand to allow caller of RpcRawCommand to deal with
the reply in the same way RpcCommand does.

Adjust test code to for the above changes.
This commit is contained in:
John C. Vernaleo 2013-08-12 12:50:04 -04:00
parent c8bb6b304e
commit 96a68227bd
4 changed files with 104 additions and 84 deletions

View file

@ -5,7 +5,6 @@
package btcjson
import (
"bytes"
"encoding/json"
"testing"
)
@ -17,76 +16,6 @@ cases which are either not possible or can't reliably be tested via the public
interface. The functions are only exported while the tests are being run.
*/
var resulttests = []struct {
cmd string
msg []byte
comp bool
pass bool
}{
// Generate a fake message to make sure we can encode and decode it and
// get the same thing back.
{"getblockcount",
[]byte(`{"result":226790,"error":{"code":1,"message":"No Error"},"id":"btcd"}`),
true, true},
// Generate a fake message to make sure we don't make a command from it.
{"anycommand", []byte(`{"result":"test","id":1}`), false, false},
{"anycommand", []byte(`{some junk}`), false, false},
{"anycommand", []byte(`{"error":null,"result":null,"id":"test"}`), false, true},
{"getinfo", []byte(`{"error":null,"result":null,"id":"test"}`), false, true},
{"getinfo", []byte(`{"error":null,"result":null}`), false, false},
{"getinfo", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getblock", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getblock", []byte(`{"result":{"hash":"000000","confirmations":16007,"size":325648},"error":null,"id":1}`), false, true},
{"getrawtransaction", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getrawtransaction", []byte(`{"error":null,"id":1,"result":{"hex":"somejunk","version":1}}`), false, true},
{"decoderawtransaction", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"decoderawtransaction", []byte(`{"error":null,"id":1,"result":{"Txid":"something"}}`), false, true},
{"getaddressesbyaccount", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getaddressesbyaccount", []byte(`{"error":null,"id":1,"result":["test"]}`), false, true},
{"getmininginfo", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getmininginfo", []byte(`{"error":null,"id":1,"result":{"generate":true}}`), false, true},
{"getrawmempool", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getrawmempool", []byte(`{"error":null,"id":1,"result":["test"]}`), false, true},
{"validateaddress", []byte(`{"error":null,"id":1,"result":{"isvalid":false}}`), false, true},
{"validateaddress", []byte(`{"error":null,"id":1,"result":{false}}`), false, false},
{"signrawtransaction", []byte(`{"error":null,"id":1,"result":{"hex":"something","complete":false}}`), false, true},
{"signrawtransaction", []byte(`{"error":null,"id":1,"result":{false}}`), false, false},
{"listunspent", []byte(`{"error":null,"id":1,"result":[{"txid":"something"}]}`), false, true},
{"listunspent", []byte(`{"error":null,"id":1,"result":[{"txid"}]}`), false, false},
}
// TestReadResultCmd tests that readResultCmd can properly unmarshall the
// returned []byte that contains a json reply for both known and unknown
// messages.
func TestReadResultCmd(t *testing.T) {
for i, tt := range resulttests {
result, err := readResultCmd(tt.cmd, tt.msg)
if tt.pass {
if err != nil {
t.Errorf("Should read result: %d %v", i, err)
}
// Due to the pointer for the Error and other structs,
// we can't always guarantee byte for byte comparison.
if tt.comp {
msg2, err := json.Marshal(result)
if err != nil {
t.Errorf("Should unmarshal result: %d %v", i, err)
}
if bytes.Compare(tt.msg, msg2) != 0 {
t.Errorf("json byte arrays differ. %d %v %v", i, tt.msg, msg2)
}
}
} else {
if err == nil {
t.Errorf("Should fail: %d, %s", i, tt.msg)
}
}
}
return
}
// TestJsonWIthArgs tests jsonWithArgs to ensure that it can generate a json
// command as well as sending it something that cannot be marshalled to json
// (a channel) to test the failure paths.

View file

@ -664,10 +664,10 @@ func CreateMessage(message string, args ...interface{}) ([]byte, error) {
return finalMessage, err
}
// readResultCmd unmarshalls the json reply with data struct for specific
// ReadResultCmd unmarshalls the json reply with data struct for specific
// commands or an interface if it is not a command where we already have a
// struct ready.
func readResultCmd(cmd string, message []byte) (Reply, error) {
func ReadResultCmd(cmd string, message []byte) (Reply, error) {
var result Reply
var err error
var objmap map[string]json.RawMessage
@ -797,21 +797,40 @@ func RpcCommand(user string, password string, server string, message []byte) (Re
err := fmt.Errorf("Error, no method specified.")
return result, err
}
body, err := RpcRawCommand(user, password, server, message)
if err != nil {
err := fmt.Errorf("Error getting json reply: %v", err)
return result, err
}
result, err = ReadResultCmd(method, body)
if err != nil {
err := fmt.Errorf("Error reading json message: %v", err)
return result, err
}
return result, err
}
// RpcRawCommand takes a message generated from one of the routines above
// along with the login/server info, sends it, and gets a reply, returning
// the raw []byte response for use with ReadResultCmd.
func RpcRawCommand(user string, password string, server string, message []byte) ([]byte, error) {
var result []byte
var msg interface{}
err := json.Unmarshal(message, &msg)
if err != nil {
err := fmt.Errorf("Error, message does not appear to be valid json: %v", err)
return result, err
}
resp, err := jsonRpcSend(user, password, server, message)
if err != nil {
err := fmt.Errorf("Error sending json message: " + err.Error())
return result, err
}
body, err := GetRaw(resp.Body)
result, err = GetRaw(resp.Body)
if err != nil {
err := fmt.Errorf("Error getting json reply: %v", err)
return result, err
}
result, err = readResultCmd(method, body)
if err != nil {
err := fmt.Errorf("Error reading json message: %v", err)
return result, err
}
return result, err
}

View file

@ -6,6 +6,7 @@ package btcjson_test
import (
"bytes"
"encoding/json"
"github.com/conformal/btcjson"
"io"
"io/ioutil"
@ -303,3 +304,73 @@ func TestJSONtoAmount(t *testing.T) {
}
return
}
var resulttests = []struct {
cmd string
msg []byte
comp bool
pass bool
}{
// Generate a fake message to make sure we can encode and decode it and
// get the same thing back.
{"getblockcount",
[]byte(`{"result":226790,"error":{"code":1,"message":"No Error"},"id":"btcd"}`),
true, true},
// Generate a fake message to make sure we don't make a command from it.
{"anycommand", []byte(`{"result":"test","id":1}`), false, false},
{"anycommand", []byte(`{some junk}`), false, false},
{"anycommand", []byte(`{"error":null,"result":null,"id":"test"}`), false, true},
{"getinfo", []byte(`{"error":null,"result":null,"id":"test"}`), false, true},
{"getinfo", []byte(`{"error":null,"result":null}`), false, false},
{"getinfo", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getblock", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getblock", []byte(`{"result":{"hash":"000000","confirmations":16007,"size":325648},"error":null,"id":1}`), false, true},
{"getrawtransaction", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getrawtransaction", []byte(`{"error":null,"id":1,"result":{"hex":"somejunk","version":1}}`), false, true},
{"decoderawtransaction", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"decoderawtransaction", []byte(`{"error":null,"id":1,"result":{"Txid":"something"}}`), false, true},
{"getaddressesbyaccount", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getaddressesbyaccount", []byte(`{"error":null,"id":1,"result":["test"]}`), false, true},
{"getmininginfo", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getmininginfo", []byte(`{"error":null,"id":1,"result":{"generate":true}}`), false, true},
{"getrawmempool", []byte(`{"error":null,"id":1,"result":[{"a":"b"}]}`), false, false},
{"getrawmempool", []byte(`{"error":null,"id":1,"result":["test"]}`), false, true},
{"validateaddress", []byte(`{"error":null,"id":1,"result":{"isvalid":false}}`), false, true},
{"validateaddress", []byte(`{"error":null,"id":1,"result":{false}}`), false, false},
{"signrawtransaction", []byte(`{"error":null,"id":1,"result":{"hex":"something","complete":false}}`), false, true},
{"signrawtransaction", []byte(`{"error":null,"id":1,"result":{false}}`), false, false},
{"listunspent", []byte(`{"error":null,"id":1,"result":[{"txid":"something"}]}`), false, true},
{"listunspent", []byte(`{"error":null,"id":1,"result":[{"txid"}]}`), false, false},
}
// TestReadResultCmd tests that readResultCmd can properly unmarshall the
// returned []byte that contains a json reply for both known and unknown
// messages.
func TestReadResultCmd(t *testing.T) {
for i, tt := range resulttests {
result, err := btcjson.ReadResultCmd(tt.cmd, tt.msg)
if tt.pass {
if err != nil {
t.Errorf("Should read result: %d %v", i, err)
}
// Due to the pointer for the Error and other structs,
// we can't always guarantee byte for byte comparison.
if tt.comp {
msg2, err := json.Marshal(result)
if err != nil {
t.Errorf("Should unmarshal result: %d %v", i, err)
}
if bytes.Compare(tt.msg, msg2) != 0 {
t.Errorf("json byte arrays differ. %d %v %v", i, tt.msg, msg2)
}
}
} else {
if err == nil {
t.Errorf("Should fail: %d, %s", i, tt.msg)
}
}
}
return
}

View file

@ -1,12 +1,13 @@
github.com/conformal/btcjson/jsonapi.go CreateMessage 100.00% (310/310)
github.com/conformal/btcjson/jsonapi.go readResultCmd 100.00% (63/63)
github.com/conformal/btcjson/jsonapi.go CreateMessage 100.00% (323/323)
github.com/conformal/btcjson/jsonapi.go ReadResultCmd 100.00% (63/63)
github.com/conformal/btcjson/jsonapi.go JSONToAmount 100.00% (15/15)
github.com/conformal/btcjson/jsonfxns.go MarshallAndSend 100.00% (7/7)
github.com/conformal/btcjson/jsonfxns.go jsonRpcSend 100.00% (7/7)
github.com/conformal/btcjson/jsonfxns.go MarshallAndSend 100.00% (7/7)
github.com/conformal/btcjson/jsonfxns.go GetRaw 100.00% (6/6)
github.com/conformal/btcjson/jsonapi.go jsonWithArgs 100.00% (5/5)
github.com/conformal/btcjson/jsonapi.go IsValidIdType 100.00% (3/3)
github.com/conformal/btcjson/jsonapi.go RpcCommand 66.67% (18/27)
github.com/conformal/btcjson --------------- 97.97% (434/443)
github.com/conformal/btcjson/jsonapi.go RpcCommand 78.26% (18/23)
github.com/conformal/btcjson/jsonapi.go RpcRawCommand 53.33% (8/15)
github.com/conformal/btcjson --------------- 97.43% (455/467)