chainsvrwscmds_test.go raw

   1  package btcjson_test
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/json"
   6  	"fmt"
   7  	"reflect"
   8  	"testing"
   9  	
  10  	"github.com/p9c/p9/pkg/btcjson"
  11  )
  12  
  13  // TestChainSvrWsCmds tests all of the chain server websocket-specific commands marshal and unmarshal into valid results
  14  // include handling of optional fields being omitted in the marshalled command, while optional fields with defaults have
  15  // the default assigned on unmarshalled commands.
  16  func TestChainSvrWsCmds(t *testing.T) {
  17  	t.Parallel()
  18  	testID := 1
  19  	tests := []struct {
  20  		name         string
  21  		newCmd       func() (interface{}, error)
  22  		staticCmd    func() interface{}
  23  		marshalled   string
  24  		unmarshalled interface{}
  25  	}{
  26  		{
  27  			name: "authenticate",
  28  			newCmd: func() (interface{}, error) {
  29  				return btcjson.NewCmd("authenticate", "user", "pass")
  30  			},
  31  			staticCmd: func() interface{} {
  32  				return btcjson.NewAuthenticateCmd("user", "pass")
  33  			},
  34  			marshalled:   `{"jsonrpc":"1.0","method":"authenticate","netparams":["user","pass"],"id":1}`,
  35  			unmarshalled: &btcjson.AuthenticateCmd{Username: "user", Passphrase: "pass"},
  36  		},
  37  		{
  38  			name: "notifyblocks",
  39  			newCmd: func() (interface{}, error) {
  40  				return btcjson.NewCmd("notifyblocks")
  41  			},
  42  			staticCmd: func() interface{} {
  43  				return btcjson.NewNotifyBlocksCmd()
  44  			},
  45  			marshalled:   `{"jsonrpc":"1.0","method":"notifyblocks","netparams":[],"id":1}`,
  46  			unmarshalled: &btcjson.NotifyBlocksCmd{},
  47  		},
  48  		{
  49  			name: "stopnotifyblocks",
  50  			newCmd: func() (interface{}, error) {
  51  				return btcjson.NewCmd("stopnotifyblocks")
  52  			},
  53  			staticCmd: func() interface{} {
  54  				return btcjson.NewStopNotifyBlocksCmd()
  55  			},
  56  			marshalled:   `{"jsonrpc":"1.0","method":"stopnotifyblocks","netparams":[],"id":1}`,
  57  			unmarshalled: &btcjson.StopNotifyBlocksCmd{},
  58  		},
  59  		{
  60  			name: "notifynewtransactions",
  61  			newCmd: func() (interface{}, error) {
  62  				return btcjson.NewCmd("notifynewtransactions")
  63  			},
  64  			staticCmd: func() interface{} {
  65  				return btcjson.NewNotifyNewTransactionsCmd(nil)
  66  			},
  67  			marshalled: `{"jsonrpc":"1.0","method":"notifynewtransactions","netparams":[],"id":1}`,
  68  			unmarshalled: &btcjson.NotifyNewTransactionsCmd{
  69  				Verbose: btcjson.Bool(false),
  70  			},
  71  		},
  72  		{
  73  			name: "notifynewtransactions optional",
  74  			newCmd: func() (interface{}, error) {
  75  				return btcjson.NewCmd("notifynewtransactions", true)
  76  			},
  77  			staticCmd: func() interface{} {
  78  				return btcjson.NewNotifyNewTransactionsCmd(btcjson.Bool(true))
  79  			},
  80  			marshalled: `{"jsonrpc":"1.0","method":"notifynewtransactions","netparams":[true],"id":1}`,
  81  			unmarshalled: &btcjson.NotifyNewTransactionsCmd{
  82  				Verbose: btcjson.Bool(true),
  83  			},
  84  		},
  85  		{
  86  			name: "stopnotifynewtransactions",
  87  			newCmd: func() (interface{}, error) {
  88  				return btcjson.NewCmd("stopnotifynewtransactions")
  89  			},
  90  			staticCmd: func() interface{} {
  91  				return btcjson.NewStopNotifyNewTransactionsCmd()
  92  			},
  93  			marshalled:   `{"jsonrpc":"1.0","method":"stopnotifynewtransactions","netparams":[],"id":1}`,
  94  			unmarshalled: &btcjson.StopNotifyNewTransactionsCmd{},
  95  		},
  96  		{
  97  			name: "notifyreceived",
  98  			newCmd: func() (interface{}, error) {
  99  				return btcjson.NewCmd("notifyreceived", []string{"1Address"})
 100  			},
 101  			staticCmd: func() interface{} {
 102  				return btcjson.NewNotifyReceivedCmd([]string{"1Address"})
 103  			},
 104  			marshalled: `{"jsonrpc":"1.0","method":"notifyreceived","netparams":[["1Address"]],"id":1}`,
 105  			unmarshalled: &btcjson.NotifyReceivedCmd{
 106  				Addresses: []string{"1Address"},
 107  			},
 108  		},
 109  		{
 110  			name: "stopnotifyreceived",
 111  			newCmd: func() (interface{}, error) {
 112  				return btcjson.NewCmd("stopnotifyreceived", []string{"1Address"})
 113  			},
 114  			staticCmd: func() interface{} {
 115  				return btcjson.NewStopNotifyReceivedCmd([]string{"1Address"})
 116  			},
 117  			marshalled: `{"jsonrpc":"1.0","method":"stopnotifyreceived","netparams":[["1Address"]],"id":1}`,
 118  			unmarshalled: &btcjson.StopNotifyReceivedCmd{
 119  				Addresses: []string{"1Address"},
 120  			},
 121  		},
 122  		{
 123  			name: "notifyspent",
 124  			newCmd: func() (interface{}, error) {
 125  				return btcjson.NewCmd("notifyspent", `[{"hash":"123","index":0}]`)
 126  			},
 127  			staticCmd: func() interface{} {
 128  				ops := []btcjson.OutPoint{{Hash: "123", Index: 0}}
 129  				return btcjson.NewNotifySpentCmd(ops)
 130  			},
 131  			marshalled: `{"jsonrpc":"1.0","method":"notifyspent","netparams":[[{"hash":"123","index":0}]],"id":1}`,
 132  			unmarshalled: &btcjson.NotifySpentCmd{
 133  				OutPoints: []btcjson.OutPoint{{Hash: "123", Index: 0}},
 134  			},
 135  		},
 136  		{
 137  			name: "stopnotifyspent",
 138  			newCmd: func() (interface{}, error) {
 139  				return btcjson.NewCmd("stopnotifyspent", `[{"hash":"123","index":0}]`)
 140  			},
 141  			staticCmd: func() interface{} {
 142  				ops := []btcjson.OutPoint{{Hash: "123", Index: 0}}
 143  				return btcjson.NewStopNotifySpentCmd(ops)
 144  			},
 145  			marshalled: `{"jsonrpc":"1.0","method":"stopnotifyspent","netparams":[[{"hash":"123","index":0}]],"id":1}`,
 146  			unmarshalled: &btcjson.StopNotifySpentCmd{
 147  				OutPoints: []btcjson.OutPoint{{Hash: "123", Index: 0}},
 148  			},
 149  		},
 150  		{
 151  			name: "rescan",
 152  			newCmd: func() (interface{}, error) {
 153  				return btcjson.NewCmd("rescan", "123", `["1Address"]`,
 154  					`[{"hash":"0000000000000000000000000000000000000000000000000000000000000123","index":0}]`,
 155  				)
 156  			},
 157  			staticCmd: func() interface{} {
 158  				addrs := []string{"1Address"}
 159  				ops := []btcjson.OutPoint{{
 160  					Hash:  "0000000000000000000000000000000000000000000000000000000000000123",
 161  					Index: 0,
 162  				},
 163  				}
 164  				return btcjson.NewRescanCmd("123", addrs, ops, nil)
 165  			},
 166  			marshalled: `{"jsonrpc":"1.0","method":"rescan","netparams":["123",["1Address"],[{"hash":"0000000000000000000000000000000000000000000000000000000000000123","index":0}]],"id":1}`,
 167  			unmarshalled: &btcjson.RescanCmd{
 168  				BeginBlock: "123",
 169  				Addresses:  []string{"1Address"},
 170  				OutPoints:  []btcjson.OutPoint{{Hash: "0000000000000000000000000000000000000000000000000000000000000123",
 171  												   Index: 0,
 172  				},
 173  				},
 174  				EndBlock:   nil,
 175  			},
 176  		},
 177  		{
 178  			name: "rescan optional",
 179  			newCmd: func() (interface{}, error) {
 180  				return btcjson.NewCmd("rescan", "123", `["1Address"]`, `[{"hash":"123","index":0}]`, "456")
 181  			},
 182  			staticCmd: func() interface{} {
 183  				addrs := []string{"1Address"}
 184  				ops := []btcjson.OutPoint{{Hash: "123", Index: 0}}
 185  				return btcjson.NewRescanCmd("123", addrs, ops, btcjson.String("456"))
 186  			},
 187  			marshalled: `{"jsonrpc":"1.0","method":"rescan","netparams":["123",["1Address"],[{"hash":"123","index":0}],"456"],"id":1}`,
 188  			unmarshalled: &btcjson.RescanCmd{
 189  				BeginBlock: "123",
 190  				Addresses:  []string{"1Address"},
 191  				OutPoints:  []btcjson.OutPoint{{Hash: "123", Index: 0}},
 192  				EndBlock:   btcjson.String("456"),
 193  			},
 194  		},
 195  		{
 196  			name: "loadtxfilter",
 197  			newCmd: func() (interface{}, error) {
 198  				return btcjson.NewCmd("loadtxfilter", false, `["1Address"]`,
 199  					`[{"hash":"0000000000000000000000000000000000000000000000000000000000000123","index":0}]`,
 200  				)
 201  			},
 202  			staticCmd: func() interface{} {
 203  				addrs := []string{"1Address"}
 204  				ops := []btcjson.OutPoint{{
 205  					Hash:  "0000000000000000000000000000000000000000000000000000000000000123",
 206  					Index: 0,
 207  				},
 208  				}
 209  				return btcjson.NewLoadTxFilterCmd(false, addrs, ops)
 210  			},
 211  			marshalled: `{"jsonrpc":"1.0","method":"loadtxfilter","netparams":[false,["1Address"],[{"hash":"0000000000000000000000000000000000000000000000000000000000000123","index":0}]],"id":1}`,
 212  			unmarshalled: &btcjson.LoadTxFilterCmd{
 213  				Reload:    false,
 214  				Addresses: []string{"1Address"},
 215  				OutPoints: []btcjson.OutPoint{{Hash: "0000000000000000000000000000000000000000000000000000000000000123",
 216  												  Index: 0,
 217  				},
 218  				},
 219  			},
 220  		},
 221  		{
 222  			name: "rescanblocks",
 223  			newCmd: func() (interface{}, error) {
 224  				return btcjson.NewCmd("rescanblocks",
 225  					`["0000000000000000000000000000000000000000000000000000000000000123"]`,
 226  				)
 227  			},
 228  			staticCmd: func() interface{} {
 229  				blockhashes := []string{"0000000000000000000000000000000000000000000000000000000000000123"}
 230  				return btcjson.NewRescanBlocksCmd(blockhashes)
 231  			},
 232  			marshalled: `{"jsonrpc":"1.0","method":"rescanblocks","netparams":[["0000000000000000000000000000000000000000000000000000000000000123"]],"id":1}`,
 233  			unmarshalled: &btcjson.RescanBlocksCmd{
 234  				BlockHashes: []string{"0000000000000000000000000000000000000000000000000000000000000123"},
 235  			},
 236  		},
 237  	}
 238  	t.Logf("Running %d tests", len(tests))
 239  	for i, test := range tests {
 240  		// Marshal the command as created by the new static command creation function.
 241  		marshalled, e := btcjson.MarshalCmd(testID, test.staticCmd())
 242  		if e != nil {
 243  			t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
 244  				test.name, e,
 245  			)
 246  			continue
 247  		}
 248  		if !bytes.Equal(marshalled, []byte(test.marshalled)) {
 249  			t.Errorf("Test #%d (%s) unexpected marshalled data - "+
 250  				"got %s, want %s", i, test.name, marshalled,
 251  				test.marshalled,
 252  			)
 253  			continue
 254  		}
 255  		// Ensure the command is created without error via the generic new command creation function.
 256  		cmd, e := test.newCmd()
 257  		if e != nil {
 258  			t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ",
 259  				i, test.name, e,
 260  			)
 261  		}
 262  		// Marshal the command as created by the generic new command creation function.
 263  		marshalled, e = btcjson.MarshalCmd(testID, cmd)
 264  		if e != nil {
 265  			t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
 266  				test.name, e,
 267  			)
 268  			continue
 269  		}
 270  		if !bytes.Equal(marshalled, []byte(test.marshalled)) {
 271  			t.Errorf("Test #%d (%s) unexpected marshalled data - "+
 272  				"got %s, want %s", i, test.name, marshalled,
 273  				test.marshalled,
 274  			)
 275  			continue
 276  		}
 277  		var request btcjson.Request
 278  		if e = json.Unmarshal(marshalled, &request); E.Chk(e) {
 279  			t.Errorf("Test #%d (%s) unexpected error while "+
 280  				"unmarshalling JSON-RPC request: %v", i,
 281  				test.name, e,
 282  			)
 283  			continue
 284  		}
 285  		cmd, e = btcjson.UnmarshalCmd(&request)
 286  		if e != nil {
 287  			t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i,
 288  				test.name, e,
 289  			)
 290  			continue
 291  		}
 292  		if !reflect.DeepEqual(cmd, test.unmarshalled) {
 293  			t.Errorf("Test #%d (%s) unexpected unmarshalled command "+
 294  				"- got %s, want %s", i, test.name,
 295  				fmt.Sprintf("(%T) %+[1]v", cmd),
 296  				fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled),
 297  			)
 298  			continue
 299  		}
 300  	}
 301  }
 302