// TestNewCmdErrors ensures the error paths of NewCmd behave as expected. func TestNewCmdErrors(t *testing.T) { t.Parallel() tests := []struct { name string method string args []interface{} err dcrjson.Error }{ { name: "unregistered command", method: "boguscommand", args: []interface{}{}, err: dcrjson.Error{Code: dcrjson.ErrUnregisteredMethod}, }, { name: "too few parameters to command with required + optional", method: "getblock", args: []interface{}{}, err: dcrjson.Error{Code: dcrjson.ErrNumParams}, }, { name: "too many parameters to command with no optional", method: "getblockcount", args: []interface{}{"123"}, err: dcrjson.Error{Code: dcrjson.ErrNumParams}, }, { name: "incorrect parameter type", method: "getblock", args: []interface{}{1}, err: dcrjson.Error{Code: dcrjson.ErrInvalidType}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { _, err := dcrjson.NewCmd(test.method, test.args...) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+ "want %T", i, test.name, err, test.err) continue } gotErrorCode := err.(dcrjson.Error).Code if gotErrorCode != test.err.Code { t.Errorf("Test #%d (%s) mismatched error code - got "+ "%v (%v), want %v", i, test.name, gotErrorCode, err, test.err.Code) continue } } }
// TestDcrWalletExtCmds tests all of the btcwallet extended commands marshal and // unmarshal into valid results include handling of optional fields being // omitted in the marshalled command, while optional fields with defaults have // the default assigned on unmarshalled commands. func TestDcrWalletExtCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "notifywinningtickets", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifywinningtickets") }, staticCmd: func() interface{} { return dcrjson.NewNotifyWinningTicketsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"notifywinningtickets","params":[],"id":1}`, unmarshalled: &dcrjson.NotifyWinningTicketsCmd{}, }, { name: "notifyspentandmissedtickets", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifyspentandmissedtickets") }, staticCmd: func() interface{} { return dcrjson.NewNotifySpentAndMissedTicketsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"notifyspentandmissedtickets","params":[],"id":1}`, unmarshalled: &dcrjson.NotifySpentAndMissedTicketsCmd{}, }, { name: "notifynewtickets", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifynewtickets") }, staticCmd: func() interface{} { return dcrjson.NewNotifyNewTicketsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"notifynewtickets","params":[],"id":1}`, unmarshalled: &dcrjson.NotifyNewTicketsCmd{}, }, { name: "notifystakedifficulty", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifystakedifficulty") }, staticCmd: func() interface{} { return dcrjson.NewNotifyStakeDifficultyCmd() }, marshalled: `{"jsonrpc":"1.0","method":"notifystakedifficulty","params":[],"id":1}`, unmarshalled: &dcrjson.NotifyStakeDifficultyCmd{}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
func execute(protected *bool, cfg *config, line string, clear *bool) bool { switch line { case "h": fmt.Printf("[h]elp print this message\n") fmt.Printf("[l]ist list all available commands\n") fmt.Printf("[p]rotect toggle protected mode (for passwords)\n") fmt.Printf("[c]lear clear command history\n") fmt.Printf("[q]uit/ctrl+d exit\n") fmt.Printf("Enter commands with arguments to execute them.\n") case "l": fallthrough case "list": listCommands() case "q": fallthrough case "quit": return true case "p": fallthrough case "protect": if *protected { *protected = false return false } *protected = true return false case "c": fallthrough case "clear": *clear = true default: args := strings.Split(line, " ") if len(args) < 1 { usage("No command specified") return false } // Ensure the specified method identifies a valid registered command and // is one of the usable types. listCmdMessageLocal := "Enter [l]ist to list commands" method := args[0] usageFlags, err := dcrjson.MethodUsageFlags(method) if err != nil { fmt.Fprintf(os.Stderr, "Unrecognized command '%s'\n", method) fmt.Fprintln(os.Stderr, listCmdMessageLocal) return false } if usageFlags&unusableFlags != 0 { fmt.Fprintf(os.Stderr, "The '%s' command can only be used via "+ "websockets\n", method) fmt.Fprintln(os.Stderr, listCmdMessageLocal) return false } // Convert remaining command line args to a slice of interface values // to be passed along as parameters to new command creation function. // // Since some commands, such as submitblock, can involve data which is // too large for the Operating System to allow as a normal command line // parameter, support using '-' as an argument to allow the argument // to be read from a stdin pipe. bio := bufio.NewReader(os.Stdin) params := make([]interface{}, 0, len(args[1:])) for _, arg := range args[1:] { if arg == "-" { param, err := bio.ReadString('\n') if err != nil && err != io.EOF { fmt.Fprintf(os.Stderr, "Failed to read data "+ "from stdin: %v\n", err) return false } if err == io.EOF && len(param) == 0 { fmt.Fprintln(os.Stderr, "Not enough lines "+ "provided on stdin") return false } param = strings.TrimRight(param, "\r\n") params = append(params, param) continue } params = append(params, arg) } // Attempt to create the appropriate command using the arguments // provided by the user. cmd, err := dcrjson.NewCmd(method, params...) if err != nil { // Show the error along with its error code when it's a // dcrjson.Error as it reallistcally will always be since the // NewCmd function is only supposed to return errors of that // type. if jerr, ok := err.(dcrjson.Error); ok { fmt.Fprintf(os.Stderr, "%s command: %v (code: %s)\n", method, err, jerr.Code) commandUsage(method) return false } // The error is not a dcrjson.Error and this really should not // happen. Nevertheless, fallback to just showing the error // if it should happen due to a bug in the package. fmt.Fprintf(os.Stderr, "%s command: %v\n", method, err) commandUsage(method) return false } // Marshal the command into a JSON-RPC byte slice in preparation for // sending it to the RPC server. marshalledJSON, err := dcrjson.MarshalCmd(1, cmd) if err != nil { fmt.Fprintln(os.Stderr, err) return false } // Send the JSON-RPC request to the server using the user-specified // connection configuration. result, err := sendPostRequest(marshalledJSON, cfg) if err != nil { fmt.Fprintln(os.Stderr, err) return false } // Choose how to display the result based on its type. strResult := string(result) if strings.HasPrefix(strResult, "{") || strings.HasPrefix(strResult, "[") { var dst bytes.Buffer if err := json.Indent(&dst, result, "", " "); err != nil { fmt.Fprintf(os.Stderr, "Failed to format result: %v\n", err) return false } fmt.Println(dst.String()) return false } else if strings.HasPrefix(strResult, `"`) { var str string if err := json.Unmarshal(result, &str); err != nil { fmt.Fprintf(os.Stderr, "Failed to unmarshal result: %v\n", err) return false } fmt.Println(str) return false } else if strResult != "null" { fmt.Println(strResult) } } return false }
// TestChainSvrWsNtfns tests all of the chain server websocket-specific // notifications marshal and unmarshal into valid results include handling of // optional fields being omitted in the marshalled command, while optional // fields with defaults have the default assigned on unmarshalled commands. func TestChainSvrWsNtfns(t *testing.T) { t.Parallel() tests := []struct { name string newNtfn func() (interface{}, error) staticNtfn func() interface{} marshalled string unmarshalled interface{} }{ { name: "blockconnected", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("blockconnected", "header", []string{"tx0", "tx1"}) }, staticNtfn: func() interface{} { return dcrjson.NewBlockConnectedNtfn("header", []string{"tx0", "tx1"}) }, marshalled: `{"jsonrpc":"1.0","method":"blockconnected","params":["header",["tx0","tx1"]],"id":null}`, unmarshalled: &dcrjson.BlockConnectedNtfn{ Header: "header", SubscribedTxs: []string{"tx0", "tx1"}, }, }, { name: "blockdisconnected", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("blockdisconnected", "header") }, staticNtfn: func() interface{} { return dcrjson.NewBlockDisconnectedNtfn("header") }, marshalled: `{"jsonrpc":"1.0","method":"blockdisconnected","params":["header"],"id":null}`, unmarshalled: &dcrjson.BlockDisconnectedNtfn{ Header: "header", }, }, { name: "relevanttxaccepted", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("relevanttxaccepted", "001122") }, staticNtfn: func() interface{} { return dcrjson.NewRelevantTxAcceptedNtfn("001122") }, marshalled: `{"jsonrpc":"1.0","method":"relevanttxaccepted","params":["001122"],"id":null}`, unmarshalled: &dcrjson.RelevantTxAcceptedNtfn{ Transaction: "001122", }, }, { name: "txaccepted", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("txaccepted", "123", 1.5) }, staticNtfn: func() interface{} { return dcrjson.NewTxAcceptedNtfn("123", 1.5) }, marshalled: `{"jsonrpc":"1.0","method":"txaccepted","params":["123",1.5],"id":null}`, unmarshalled: &dcrjson.TxAcceptedNtfn{ TxID: "123", Amount: 1.5, }, }, { name: "txacceptedverbose", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("txacceptedverbose", `{"hex":"001122","txid":"123","version":1,"locktime":4294967295,"vin":null,"vout":null,"confirmations":0}`) }, staticNtfn: func() interface{} { txResult := dcrjson.TxRawResult{ Hex: "001122", Txid: "123", Version: 1, LockTime: 4294967295, Vin: nil, Vout: nil, Confirmations: 0, } return dcrjson.NewTxAcceptedVerboseNtfn(txResult) }, marshalled: `{"jsonrpc":"1.0","method":"txacceptedverbose","params":[{"hex":"001122","txid":"123","version":1,"locktime":4294967295,"expiry":0,"vin":null,"vout":null,"blockheight":0}],"id":null}`, unmarshalled: &dcrjson.TxAcceptedVerboseNtfn{ RawTx: dcrjson.TxRawResult{ Hex: "001122", Txid: "123", Version: 1, LockTime: 4294967295, Vin: nil, Vout: nil, Confirmations: 0, }, }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the notification as created by the new static // creation function. The ID is nil for notifications. marshalled, err := dcrjson.MarshalCmd(nil, test.staticNtfn()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the notification is created without error via the // generic new notification creation function. cmd, err := test.newNtfn() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the notification as created by the generic new // notification creation function. The ID is nil for // notifications. marshalled, err = dcrjson.MarshalCmd(nil, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and // unmarshal into valid results include handling of optional fields being // omitted in the marshalled command, while optional fields with defaults have // the default assigned on unmarshalled commands. func TestBtcWalletExtCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "createnewaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("createnewaccount", "acct") }, staticCmd: func() interface{} { return dcrjson.NewCreateNewAccountCmd("acct") }, marshalled: `{"jsonrpc":"1.0","method":"createnewaccount","params":["acct"],"id":1}`, unmarshalled: &dcrjson.CreateNewAccountCmd{ Account: "acct", }, }, { name: "dumpwallet", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("dumpwallet", "filename") }, staticCmd: func() interface{} { return dcrjson.NewDumpWalletCmd("filename") }, marshalled: `{"jsonrpc":"1.0","method":"dumpwallet","params":["filename"],"id":1}`, unmarshalled: &dcrjson.DumpWalletCmd{ Filename: "filename", }, }, { name: "importaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importaddress", "1Address") }, staticCmd: func() interface{} { return dcrjson.NewImportAddressCmd("1Address", nil) }, marshalled: `{"jsonrpc":"1.0","method":"importaddress","params":["1Address"],"id":1}`, unmarshalled: &dcrjson.ImportAddressCmd{ Address: "1Address", Rescan: dcrjson.Bool(true), }, }, { name: "importaddress optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importaddress", "1Address", false) }, staticCmd: func() interface{} { return dcrjson.NewImportAddressCmd("1Address", dcrjson.Bool(false)) }, marshalled: `{"jsonrpc":"1.0","method":"importaddress","params":["1Address",false],"id":1}`, unmarshalled: &dcrjson.ImportAddressCmd{ Address: "1Address", Rescan: dcrjson.Bool(false), }, }, { name: "importpubkey", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importpubkey", "031234") }, staticCmd: func() interface{} { return dcrjson.NewImportPubKeyCmd("031234", nil) }, marshalled: `{"jsonrpc":"1.0","method":"importpubkey","params":["031234"],"id":1}`, unmarshalled: &dcrjson.ImportPubKeyCmd{ PubKey: "031234", Rescan: dcrjson.Bool(true), }, }, { name: "importpubkey optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importpubkey", "031234", false) }, staticCmd: func() interface{} { return dcrjson.NewImportPubKeyCmd("031234", dcrjson.Bool(false)) }, marshalled: `{"jsonrpc":"1.0","method":"importpubkey","params":["031234",false],"id":1}`, unmarshalled: &dcrjson.ImportPubKeyCmd{ PubKey: "031234", Rescan: dcrjson.Bool(false), }, }, { name: "importwallet", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importwallet", "filename") }, staticCmd: func() interface{} { return dcrjson.NewImportWalletCmd("filename") }, marshalled: `{"jsonrpc":"1.0","method":"importwallet","params":["filename"],"id":1}`, unmarshalled: &dcrjson.ImportWalletCmd{ Filename: "filename", }, }, { name: "renameaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("renameaccount", "oldacct", "newacct") }, staticCmd: func() interface{} { return dcrjson.NewRenameAccountCmd("oldacct", "newacct") }, marshalled: `{"jsonrpc":"1.0","method":"renameaccount","params":["oldacct","newacct"],"id":1}`, unmarshalled: &dcrjson.RenameAccountCmd{ OldAccount: "oldacct", NewAccount: "newacct", }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal // into valid results include handling of optional fields being omitted in the // marshalled command, while optional fields with defaults have the default // assigned on unmarshalled commands. func TestBtcdExtCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "debuglevel", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("debuglevel", "trace") }, staticCmd: func() interface{} { return dcrjson.NewDebugLevelCmd("trace") }, marshalled: `{"jsonrpc":"1.0","method":"debuglevel","params":["trace"],"id":1}`, unmarshalled: &dcrjson.DebugLevelCmd{ LevelSpec: "trace", }, }, { name: "node", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("node", dcrjson.NRemove, "1.1.1.1") }, staticCmd: func() interface{} { return dcrjson.NewNodeCmd("remove", "1.1.1.1", nil) }, marshalled: `{"jsonrpc":"1.0","method":"node","params":["remove","1.1.1.1"],"id":1}`, unmarshalled: &dcrjson.NodeCmd{ SubCmd: dcrjson.NRemove, Target: "1.1.1.1", }, }, { name: "node", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("node", dcrjson.NDisconnect, "1.1.1.1") }, staticCmd: func() interface{} { return dcrjson.NewNodeCmd("disconnect", "1.1.1.1", nil) }, marshalled: `{"jsonrpc":"1.0","method":"node","params":["disconnect","1.1.1.1"],"id":1}`, unmarshalled: &dcrjson.NodeCmd{ SubCmd: dcrjson.NDisconnect, Target: "1.1.1.1", }, }, { name: "node", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("node", dcrjson.NConnect, "1.1.1.1", "perm") }, staticCmd: func() interface{} { return dcrjson.NewNodeCmd("connect", "1.1.1.1", dcrjson.String("perm")) }, marshalled: `{"jsonrpc":"1.0","method":"node","params":["connect","1.1.1.1","perm"],"id":1}`, unmarshalled: &dcrjson.NodeCmd{ SubCmd: dcrjson.NConnect, Target: "1.1.1.1", ConnectSubCmd: dcrjson.String("perm"), }, }, { name: "node", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("node", dcrjson.NConnect, "1.1.1.1", "temp") }, staticCmd: func() interface{} { return dcrjson.NewNodeCmd("connect", "1.1.1.1", dcrjson.String("temp")) }, marshalled: `{"jsonrpc":"1.0","method":"node","params":["connect","1.1.1.1","temp"],"id":1}`, unmarshalled: &dcrjson.NodeCmd{ SubCmd: dcrjson.NConnect, Target: "1.1.1.1", ConnectSubCmd: dcrjson.String("temp"), }, }, { name: "generate", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("generate", 1) }, staticCmd: func() interface{} { return dcrjson.NewGenerateCmd(1) }, marshalled: `{"jsonrpc":"1.0","method":"generate","params":[1],"id":1}`, unmarshalled: &dcrjson.GenerateCmd{ NumBlocks: 1, }, }, { name: "getbestblock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getbestblock") }, staticCmd: func() interface{} { return dcrjson.NewGetBestBlockCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getbestblock","params":[],"id":1}`, unmarshalled: &dcrjson.GetBestBlockCmd{}, }, { name: "getcurrentnet", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getcurrentnet") }, staticCmd: func() interface{} { return dcrjson.NewGetCurrentNetCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getcurrentnet","params":[],"id":1}`, unmarshalled: &dcrjson.GetCurrentNetCmd{}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal // into valid results include handling of optional fields being omitted in the // marshalled command, while optional fields with defaults have the default // assigned on unmarshalled commands. func TestChainSvrCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "addnode", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("addnode", "127.0.0.1", dcrjson.ANRemove) }, staticCmd: func() interface{} { return dcrjson.NewAddNodeCmd("127.0.0.1", dcrjson.ANRemove) }, marshalled: `{"jsonrpc":"1.0","method":"addnode","params":["127.0.0.1","remove"],"id":1}`, unmarshalled: &dcrjson.AddNodeCmd{Addr: "127.0.0.1", SubCmd: dcrjson.ANRemove}, }, { name: "createrawtransaction", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`, `{"456":0.0123}`) }, staticCmd: func() interface{} { txInputs := []dcrjson.TransactionInput{ {Txid: "123", Vout: 1}, } amounts := map[string]float64{"456": .0123} return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts, nil) }, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1,"tree":0}],{"456":0.0123}],"id":1}`, unmarshalled: &dcrjson.CreateRawTransactionCmd{ Inputs: []dcrjson.TransactionInput{{Txid: "123", Vout: 1}}, Amounts: map[string]float64{"456": .0123}, }, }, { name: "createrawtransaction optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1,"tree":0}]`, `{"456":0.0123}`, int64(12312333333)) }, staticCmd: func() interface{} { txInputs := []dcrjson.TransactionInput{ {Txid: "123", Vout: 1}, } amounts := map[string]float64{"456": .0123} return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts, dcrjson.Int64(12312333333)) }, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1,"tree":0}],{"456":0.0123},12312333333],"id":1}`, unmarshalled: &dcrjson.CreateRawTransactionCmd{ Inputs: []dcrjson.TransactionInput{{Txid: "123", Vout: 1}}, Amounts: map[string]float64{"456": .0123}, LockTime: dcrjson.Int64(12312333333), }, }, { name: "decoderawtransaction", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("decoderawtransaction", "123") }, staticCmd: func() interface{} { return dcrjson.NewDecodeRawTransactionCmd("123") }, marshalled: `{"jsonrpc":"1.0","method":"decoderawtransaction","params":["123"],"id":1}`, unmarshalled: &dcrjson.DecodeRawTransactionCmd{HexTx: "123"}, }, { name: "decodescript", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("decodescript", "00") }, staticCmd: func() interface{} { return dcrjson.NewDecodeScriptCmd("00") }, marshalled: `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`, unmarshalled: &dcrjson.DecodeScriptCmd{HexScript: "00"}, }, { name: "getaddednodeinfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getaddednodeinfo", true) }, staticCmd: func() interface{} { return dcrjson.NewGetAddedNodeInfoCmd(true, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getaddednodeinfo","params":[true],"id":1}`, unmarshalled: &dcrjson.GetAddedNodeInfoCmd{DNS: true, Node: nil}, }, { name: "getaddednodeinfo optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getaddednodeinfo", true, "127.0.0.1") }, staticCmd: func() interface{} { return dcrjson.NewGetAddedNodeInfoCmd(true, dcrjson.String("127.0.0.1")) }, marshalled: `{"jsonrpc":"1.0","method":"getaddednodeinfo","params":[true,"127.0.0.1"],"id":1}`, unmarshalled: &dcrjson.GetAddedNodeInfoCmd{ DNS: true, Node: dcrjson.String("127.0.0.1"), }, }, { name: "getbestblockhash", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getbestblockhash") }, staticCmd: func() interface{} { return dcrjson.NewGetBestBlockHashCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getbestblockhash","params":[],"id":1}`, unmarshalled: &dcrjson.GetBestBlockHashCmd{}, }, { name: "getblock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblock", "123") }, staticCmd: func() interface{} { return dcrjson.NewGetBlockCmd("123", nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`, unmarshalled: &dcrjson.GetBlockCmd{ Hash: "123", Verbose: dcrjson.Bool(true), VerboseTx: dcrjson.Bool(false), }, }, { name: "getblock required optional1", newCmd: func() (interface{}, error) { // Intentionally use a source param that is // more pointers than the destination to // exercise that path. verbosePtr := dcrjson.Bool(true) return dcrjson.NewCmd("getblock", "123", &verbosePtr) }, staticCmd: func() interface{} { return dcrjson.NewGetBlockCmd("123", dcrjson.Bool(true), nil) }, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true],"id":1}`, unmarshalled: &dcrjson.GetBlockCmd{ Hash: "123", Verbose: dcrjson.Bool(true), VerboseTx: dcrjson.Bool(false), }, }, { name: "getblock required optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblock", "123", true, true) }, staticCmd: func() interface{} { return dcrjson.NewGetBlockCmd("123", dcrjson.Bool(true), dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true,true],"id":1}`, unmarshalled: &dcrjson.GetBlockCmd{ Hash: "123", Verbose: dcrjson.Bool(true), VerboseTx: dcrjson.Bool(true), }, }, { name: "getblockchaininfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblockchaininfo") }, staticCmd: func() interface{} { return dcrjson.NewGetBlockChainInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getblockchaininfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetBlockChainInfoCmd{}, }, { name: "getblockcount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblockcount") }, staticCmd: func() interface{} { return dcrjson.NewGetBlockCountCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getblockcount","params":[],"id":1}`, unmarshalled: &dcrjson.GetBlockCountCmd{}, }, { name: "getblockhash", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblockhash", 123) }, staticCmd: func() interface{} { return dcrjson.NewGetBlockHashCmd(123) }, marshalled: `{"jsonrpc":"1.0","method":"getblockhash","params":[123],"id":1}`, unmarshalled: &dcrjson.GetBlockHashCmd{Index: 123}, }, { name: "getblockheader", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblockheader", "123") }, staticCmd: func() interface{} { return dcrjson.NewGetBlockHeaderCmd("123", nil) }, marshalled: `{"jsonrpc":"1.0","method":"getblockheader","params":["123"],"id":1}`, unmarshalled: &dcrjson.GetBlockHeaderCmd{ Hash: "123", Verbose: dcrjson.Bool(true), }, }, { name: "getblocktemplate", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblocktemplate") }, staticCmd: func() interface{} { return dcrjson.NewGetBlockTemplateCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[],"id":1}`, unmarshalled: &dcrjson.GetBlockTemplateCmd{Request: nil}, }, { name: "getblocktemplate optional - template request", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"]}`) }, staticCmd: func() interface{} { template := dcrjson.TemplateRequest{ Mode: "template", Capabilities: []string{"longpoll", "coinbasetxn"}, } return dcrjson.NewGetBlockTemplateCmd(&template) }, marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"]}],"id":1}`, unmarshalled: &dcrjson.GetBlockTemplateCmd{ Request: &dcrjson.TemplateRequest{ Mode: "template", Capabilities: []string{"longpoll", "coinbasetxn"}, }, }, }, { name: "getblocktemplate optional - template request with tweaks", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":500,"sizelimit":100000000,"maxversion":2}`) }, staticCmd: func() interface{} { template := dcrjson.TemplateRequest{ Mode: "template", Capabilities: []string{"longpoll", "coinbasetxn"}, SigOpLimit: 500, SizeLimit: 100000000, MaxVersion: 2, } return dcrjson.NewGetBlockTemplateCmd(&template) }, marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":500,"sizelimit":100000000,"maxversion":2}],"id":1}`, unmarshalled: &dcrjson.GetBlockTemplateCmd{ Request: &dcrjson.TemplateRequest{ Mode: "template", Capabilities: []string{"longpoll", "coinbasetxn"}, SigOpLimit: int64(500), SizeLimit: int64(100000000), MaxVersion: 2, }, }, }, { name: "getblocktemplate optional - template request with tweaks 2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":true,"sizelimit":100000000,"maxversion":2}`) }, staticCmd: func() interface{} { template := dcrjson.TemplateRequest{ Mode: "template", Capabilities: []string{"longpoll", "coinbasetxn"}, SigOpLimit: true, SizeLimit: 100000000, MaxVersion: 2, } return dcrjson.NewGetBlockTemplateCmd(&template) }, marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":true,"sizelimit":100000000,"maxversion":2}],"id":1}`, unmarshalled: &dcrjson.GetBlockTemplateCmd{ Request: &dcrjson.TemplateRequest{ Mode: "template", Capabilities: []string{"longpoll", "coinbasetxn"}, SigOpLimit: true, SizeLimit: int64(100000000), MaxVersion: 2, }, }, }, { name: "getchaintips", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getchaintips") }, staticCmd: func() interface{} { return dcrjson.NewGetChainTipsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getchaintips","params":[],"id":1}`, unmarshalled: &dcrjson.GetChainTipsCmd{}, }, { name: "getconnectioncount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getconnectioncount") }, staticCmd: func() interface{} { return dcrjson.NewGetConnectionCountCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getconnectioncount","params":[],"id":1}`, unmarshalled: &dcrjson.GetConnectionCountCmd{}, }, { name: "getdifficulty", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getdifficulty") }, staticCmd: func() interface{} { return dcrjson.NewGetDifficultyCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getdifficulty","params":[],"id":1}`, unmarshalled: &dcrjson.GetDifficultyCmd{}, }, { name: "getgenerate", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getgenerate") }, staticCmd: func() interface{} { return dcrjson.NewGetGenerateCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getgenerate","params":[],"id":1}`, unmarshalled: &dcrjson.GetGenerateCmd{}, }, { name: "gethashespersec", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gethashespersec") }, staticCmd: func() interface{} { return dcrjson.NewGetHashesPerSecCmd() }, marshalled: `{"jsonrpc":"1.0","method":"gethashespersec","params":[],"id":1}`, unmarshalled: &dcrjson.GetHashesPerSecCmd{}, }, { name: "getinfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getinfo") }, staticCmd: func() interface{} { return dcrjson.NewGetInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getinfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetInfoCmd{}, }, { name: "getmempoolinfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getmempoolinfo") }, staticCmd: func() interface{} { return dcrjson.NewGetMempoolInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getmempoolinfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetMempoolInfoCmd{}, }, { name: "getmininginfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getmininginfo") }, staticCmd: func() interface{} { return dcrjson.NewGetMiningInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getmininginfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetMiningInfoCmd{}, }, { name: "getnetworkinfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnetworkinfo") }, staticCmd: func() interface{} { return dcrjson.NewGetNetworkInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getnetworkinfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetNetworkInfoCmd{}, }, { name: "getnettotals", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnettotals") }, staticCmd: func() interface{} { return dcrjson.NewGetNetTotalsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getnettotals","params":[],"id":1}`, unmarshalled: &dcrjson.GetNetTotalsCmd{}, }, { name: "getnetworkhashps", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnetworkhashps") }, staticCmd: func() interface{} { return dcrjson.NewGetNetworkHashPSCmd(nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[],"id":1}`, unmarshalled: &dcrjson.GetNetworkHashPSCmd{ Blocks: dcrjson.Int(120), Height: dcrjson.Int(-1), }, }, { name: "getnetworkhashps optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnetworkhashps", 200) }, staticCmd: func() interface{} { return dcrjson.NewGetNetworkHashPSCmd(dcrjson.Int(200), nil) }, marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[200],"id":1}`, unmarshalled: &dcrjson.GetNetworkHashPSCmd{ Blocks: dcrjson.Int(200), Height: dcrjson.Int(-1), }, }, { name: "getnetworkhashps optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnetworkhashps", 200, 123) }, staticCmd: func() interface{} { return dcrjson.NewGetNetworkHashPSCmd(dcrjson.Int(200), dcrjson.Int(123)) }, marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[200,123],"id":1}`, unmarshalled: &dcrjson.GetNetworkHashPSCmd{ Blocks: dcrjson.Int(200), Height: dcrjson.Int(123), }, }, { name: "getpeerinfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getpeerinfo") }, staticCmd: func() interface{} { return dcrjson.NewGetPeerInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"getpeerinfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetPeerInfoCmd{}, }, { name: "getrawmempool", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawmempool") }, staticCmd: func() interface{} { return dcrjson.NewGetRawMempoolCmd(nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[],"id":1}`, unmarshalled: &dcrjson.GetRawMempoolCmd{ Verbose: dcrjson.Bool(false), }, }, { name: "getrawmempool optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawmempool", false) }, staticCmd: func() interface{} { return dcrjson.NewGetRawMempoolCmd(dcrjson.Bool(false), nil) }, marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[false],"id":1}`, unmarshalled: &dcrjson.GetRawMempoolCmd{ Verbose: dcrjson.Bool(false), }, }, { name: "getrawmempool optional 2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawmempool", false, "all") }, staticCmd: func() interface{} { return dcrjson.NewGetRawMempoolCmd(dcrjson.Bool(false), dcrjson.String("all")) }, marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[false,"all"],"id":1}`, unmarshalled: &dcrjson.GetRawMempoolCmd{ Verbose: dcrjson.Bool(false), TxType: dcrjson.String("all"), }, }, { name: "getrawtransaction", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawtransaction", "123") }, staticCmd: func() interface{} { return dcrjson.NewGetRawTransactionCmd("123", nil) }, marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`, unmarshalled: &dcrjson.GetRawTransactionCmd{ Txid: "123", Verbose: dcrjson.Int(0), }, }, { name: "getrawtransaction optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawtransaction", "123", 1) }, staticCmd: func() interface{} { return dcrjson.NewGetRawTransactionCmd("123", dcrjson.Int(1)) }, marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",1],"id":1}`, unmarshalled: &dcrjson.GetRawTransactionCmd{ Txid: "123", Verbose: dcrjson.Int(1), }, }, { name: "gettxout", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettxout", "123", 1) }, staticCmd: func() interface{} { return dcrjson.NewGetTxOutCmd("123", 1, nil) }, marshalled: `{"jsonrpc":"1.0","method":"gettxout","params":["123",1],"id":1}`, unmarshalled: &dcrjson.GetTxOutCmd{ Txid: "123", Vout: 1, IncludeMempool: dcrjson.Bool(true), }, }, { name: "gettxout optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettxout", "123", 1, true) }, staticCmd: func() interface{} { return dcrjson.NewGetTxOutCmd("123", 1, dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"gettxout","params":["123",1,true],"id":1}`, unmarshalled: &dcrjson.GetTxOutCmd{ Txid: "123", Vout: 1, IncludeMempool: dcrjson.Bool(true), }, }, { name: "gettxoutproof", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettxoutproof", []string{"123", "456"}) }, staticCmd: func() interface{} { return dcrjson.NewGetTxOutProofCmd([]string{"123", "456"}, nil) }, marshalled: `{"jsonrpc":"1.0","method":"gettxoutproof","params":[["123","456"]],"id":1}`, unmarshalled: &dcrjson.GetTxOutProofCmd{ TxIDs: []string{"123", "456"}, }, }, { name: "gettxoutproof optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettxoutproof", []string{"123", "456"}, dcrjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf")) }, staticCmd: func() interface{} { return dcrjson.NewGetTxOutProofCmd([]string{"123", "456"}, dcrjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf")) }, marshalled: `{"jsonrpc":"1.0","method":"gettxoutproof","params":[["123","456"],` + `"000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"],"id":1}`, unmarshalled: &dcrjson.GetTxOutProofCmd{ TxIDs: []string{"123", "456"}, BlockHash: dcrjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"), }, }, { name: "gettxoutsetinfo", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettxoutsetinfo") }, staticCmd: func() interface{} { return dcrjson.NewGetTxOutSetInfoCmd() }, marshalled: `{"jsonrpc":"1.0","method":"gettxoutsetinfo","params":[],"id":1}`, unmarshalled: &dcrjson.GetTxOutSetInfoCmd{}, }, { name: "getwork", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getwork") }, staticCmd: func() interface{} { return dcrjson.NewGetWorkCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"getwork","params":[],"id":1}`, unmarshalled: &dcrjson.GetWorkCmd{ Data: nil, }, }, { name: "getwork optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getwork", "00112233") }, staticCmd: func() interface{} { return dcrjson.NewGetWorkCmd(dcrjson.String("00112233")) }, marshalled: `{"jsonrpc":"1.0","method":"getwork","params":["00112233"],"id":1}`, unmarshalled: &dcrjson.GetWorkCmd{ Data: dcrjson.String("00112233"), }, }, { name: "help", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("help") }, staticCmd: func() interface{} { return dcrjson.NewHelpCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"help","params":[],"id":1}`, unmarshalled: &dcrjson.HelpCmd{ Command: nil, }, }, { name: "help optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("help", "getblock") }, staticCmd: func() interface{} { return dcrjson.NewHelpCmd(dcrjson.String("getblock")) }, marshalled: `{"jsonrpc":"1.0","method":"help","params":["getblock"],"id":1}`, unmarshalled: &dcrjson.HelpCmd{ Command: dcrjson.String("getblock"), }, }, { name: "invalidateblock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("invalidateblock", "123") }, staticCmd: func() interface{} { return dcrjson.NewInvalidateBlockCmd("123") }, marshalled: `{"jsonrpc":"1.0","method":"invalidateblock","params":["123"],"id":1}`, unmarshalled: &dcrjson.InvalidateBlockCmd{ BlockHash: "123", }, }, { name: "ping", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("ping") }, staticCmd: func() interface{} { return dcrjson.NewPingCmd() }, marshalled: `{"jsonrpc":"1.0","method":"ping","params":[],"id":1}`, unmarshalled: &dcrjson.PingCmd{}, }, { name: "reconsiderblock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("reconsiderblock", "123") }, staticCmd: func() interface{} { return dcrjson.NewReconsiderBlockCmd("123") }, marshalled: `{"jsonrpc":"1.0","method":"reconsiderblock","params":["123"],"id":1}`, unmarshalled: &dcrjson.ReconsiderBlockCmd{ BlockHash: "123", }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address") }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", nil, nil, nil, nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address"],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(1), Skip: dcrjson.Int(0), Count: dcrjson.Int(100), VinExtra: dcrjson.Int(0), Reverse: dcrjson.Bool(false), FilterAddrs: nil, }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address", 0) }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", dcrjson.Int(0), nil, nil, nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(0), Skip: dcrjson.Int(0), Count: dcrjson.Int(100), VinExtra: dcrjson.Int(0), Reverse: dcrjson.Bool(false), FilterAddrs: nil, }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address", 0, 5) }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", dcrjson.Int(0), dcrjson.Int(5), nil, nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(0), Skip: dcrjson.Int(5), Count: dcrjson.Int(100), VinExtra: dcrjson.Int(0), Reverse: dcrjson.Bool(false), FilterAddrs: nil, }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10) }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", dcrjson.Int(0), dcrjson.Int(5), dcrjson.Int(10), nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(0), Skip: dcrjson.Int(5), Count: dcrjson.Int(10), VinExtra: dcrjson.Int(0), Reverse: dcrjson.Bool(false), FilterAddrs: nil, }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1) }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", dcrjson.Int(0), dcrjson.Int(5), dcrjson.Int(10), dcrjson.Int(1), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(0), Skip: dcrjson.Int(5), Count: dcrjson.Int(10), VinExtra: dcrjson.Int(1), Reverse: dcrjson.Bool(false), FilterAddrs: nil, }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1, true) }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", dcrjson.Int(0), dcrjson.Int(5), dcrjson.Int(10), dcrjson.Int(1), dcrjson.Bool(true), nil) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1,true],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(0), Skip: dcrjson.Int(5), Count: dcrjson.Int(10), VinExtra: dcrjson.Int(1), Reverse: dcrjson.Bool(true), FilterAddrs: nil, }, }, { name: "searchrawtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1, true, []string{"1Address"}) }, staticCmd: func() interface{} { return dcrjson.NewSearchRawTransactionsCmd("1Address", dcrjson.Int(0), dcrjson.Int(5), dcrjson.Int(10), dcrjson.Int(1), dcrjson.Bool(true), &[]string{"1Address"}) }, marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1,true,["1Address"]],"id":1}`, unmarshalled: &dcrjson.SearchRawTransactionsCmd{ Address: "1Address", Verbose: dcrjson.Int(0), Skip: dcrjson.Int(5), Count: dcrjson.Int(10), VinExtra: dcrjson.Int(1), Reverse: dcrjson.Bool(true), FilterAddrs: &[]string{"1Address"}, }, }, { name: "sendrawtransaction", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendrawtransaction", "1122") }, staticCmd: func() interface{} { return dcrjson.NewSendRawTransactionCmd("1122", nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122"],"id":1}`, unmarshalled: &dcrjson.SendRawTransactionCmd{ HexTx: "1122", AllowHighFees: dcrjson.Bool(false), }, }, { name: "sendrawtransaction optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendrawtransaction", "1122", false) }, staticCmd: func() interface{} { return dcrjson.NewSendRawTransactionCmd("1122", dcrjson.Bool(false)) }, marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`, unmarshalled: &dcrjson.SendRawTransactionCmd{ HexTx: "1122", AllowHighFees: dcrjson.Bool(false), }, }, { name: "setgenerate", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("setgenerate", true) }, staticCmd: func() interface{} { return dcrjson.NewSetGenerateCmd(true, nil) }, marshalled: `{"jsonrpc":"1.0","method":"setgenerate","params":[true],"id":1}`, unmarshalled: &dcrjson.SetGenerateCmd{ Generate: true, GenProcLimit: dcrjson.Int(-1), }, }, { name: "setgenerate optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("setgenerate", true, 6) }, staticCmd: func() interface{} { return dcrjson.NewSetGenerateCmd(true, dcrjson.Int(6)) }, marshalled: `{"jsonrpc":"1.0","method":"setgenerate","params":[true,6],"id":1}`, unmarshalled: &dcrjson.SetGenerateCmd{ Generate: true, GenProcLimit: dcrjson.Int(6), }, }, { name: "stop", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("stop") }, staticCmd: func() interface{} { return dcrjson.NewStopCmd() }, marshalled: `{"jsonrpc":"1.0","method":"stop","params":[],"id":1}`, unmarshalled: &dcrjson.StopCmd{}, }, { name: "submitblock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("submitblock", "112233") }, staticCmd: func() interface{} { return dcrjson.NewSubmitBlockCmd("112233", nil) }, marshalled: `{"jsonrpc":"1.0","method":"submitblock","params":["112233"],"id":1}`, unmarshalled: &dcrjson.SubmitBlockCmd{ HexBlock: "112233", Options: nil, }, }, { name: "submitblock optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("submitblock", "112233", `{"workid":"12345"}`) }, staticCmd: func() interface{} { options := dcrjson.SubmitBlockOptions{ WorkID: "12345", } return dcrjson.NewSubmitBlockCmd("112233", &options) }, marshalled: `{"jsonrpc":"1.0","method":"submitblock","params":["112233",{"workid":"12345"}],"id":1}`, unmarshalled: &dcrjson.SubmitBlockCmd{ HexBlock: "112233", Options: &dcrjson.SubmitBlockOptions{ WorkID: "12345", }, }, }, { name: "validateaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("validateaddress", "1Address") }, staticCmd: func() interface{} { return dcrjson.NewValidateAddressCmd("1Address") }, marshalled: `{"jsonrpc":"1.0","method":"validateaddress","params":["1Address"],"id":1}`, unmarshalled: &dcrjson.ValidateAddressCmd{ Address: "1Address", }, }, { name: "verifychain", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("verifychain") }, staticCmd: func() interface{} { return dcrjson.NewVerifyChainCmd(nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[],"id":1}`, unmarshalled: &dcrjson.VerifyChainCmd{ CheckLevel: dcrjson.Int64(3), CheckDepth: dcrjson.Int64(288), }, }, { name: "verifychain optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("verifychain", 2) }, staticCmd: func() interface{} { return dcrjson.NewVerifyChainCmd(dcrjson.Int64(2), nil) }, marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[2],"id":1}`, unmarshalled: &dcrjson.VerifyChainCmd{ CheckLevel: dcrjson.Int64(2), CheckDepth: dcrjson.Int64(288), }, }, { name: "verifychain optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("verifychain", 2, 500) }, staticCmd: func() interface{} { return dcrjson.NewVerifyChainCmd(dcrjson.Int64(2), dcrjson.Int64(500)) }, marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[2,500],"id":1}`, unmarshalled: &dcrjson.VerifyChainCmd{ CheckLevel: dcrjson.Int64(2), CheckDepth: dcrjson.Int64(500), }, }, { name: "verifymessage", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("verifymessage", "1Address", "301234", "test") }, staticCmd: func() interface{} { return dcrjson.NewVerifyMessageCmd("1Address", "301234", "test") }, marshalled: `{"jsonrpc":"1.0","method":"verifymessage","params":["1Address","301234","test"],"id":1}`, unmarshalled: &dcrjson.VerifyMessageCmd{ Address: "1Address", Signature: "301234", Message: "test", }, }, { name: "verifytxoutproof", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("verifytxoutproof", "test") }, staticCmd: func() interface{} { return dcrjson.NewVerifyTxOutProofCmd("test") }, marshalled: `{"jsonrpc":"1.0","method":"verifytxoutproof","params":["test"],"id":1}`, unmarshalled: &dcrjson.VerifyTxOutProofCmd{ Proof: "test", }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) t.Errorf("\n%s\n%s", marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestWalletSvrWsNtfns tests all of the chain server websocket-specific // notifications marshal and unmarshal into valid results include handling of // optional fields being omitted in the marshalled command, while optional // fields with defaults have the default assigned on unmarshalled commands. func TestWalletSvrWsNtfns(t *testing.T) { t.Parallel() tests := []struct { name string newNtfn func() (interface{}, error) staticNtfn func() interface{} marshalled string unmarshalled interface{} }{ { name: "accountbalance", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("accountbalance", "acct", 1.25, true) }, staticNtfn: func() interface{} { return dcrjson.NewAccountBalanceNtfn("acct", 1.25, true) }, marshalled: `{"jsonrpc":"1.0","method":"accountbalance","params":["acct",1.25,true],"id":null}`, unmarshalled: &dcrjson.AccountBalanceNtfn{ Account: "acct", Balance: 1.25, Confirmed: true, }, }, { name: "dcrdconnected", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("dcrdconnected", true) }, staticNtfn: func() interface{} { return dcrjson.NewBtcdConnectedNtfn(true) }, marshalled: `{"jsonrpc":"1.0","method":"dcrdconnected","params":[true],"id":null}`, unmarshalled: &dcrjson.BtcdConnectedNtfn{ Connected: true, }, }, { name: "walletlockstate", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("walletlockstate", true) }, staticNtfn: func() interface{} { return dcrjson.NewWalletLockStateNtfn(true) }, marshalled: `{"jsonrpc":"1.0","method":"walletlockstate","params":[true],"id":null}`, unmarshalled: &dcrjson.WalletLockStateNtfn{ Locked: true, }, }, { name: "newtx", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("newtx", "acct", `{"account":"acct","address":"1Address","category":"send","amount":1.5,"fee":0.0001,"confirmations":1,"txid":"456","walletconflicts":[],"time":12345678,"timereceived":12345876,"vout":789,"otheraccount":"otheracct"}`) }, staticNtfn: func() interface{} { result := dcrjson.ListTransactionsResult{ Account: "acct", Address: "1Address", Category: "send", Amount: 1.5, Fee: dcrjson.Float64(0.0001), Confirmations: 1, TxID: "456", WalletConflicts: []string{}, Time: 12345678, TimeReceived: 12345876, Vout: 789, OtherAccount: "otheracct", } return dcrjson.NewNewTxNtfn("acct", result) }, marshalled: `{"jsonrpc":"1.0","method":"newtx","params":["acct",{"account":"acct","address":"1Address","amount":1.5,"category":"send","confirmations":1,"fee":0.0001,"time":12345678,"timereceived":12345876,"txid":"456","vout":789,"walletconflicts":[],"otheraccount":"otheracct"}],"id":null}`, unmarshalled: &dcrjson.NewTxNtfn{ Account: "acct", Details: dcrjson.ListTransactionsResult{ Account: "acct", Address: "1Address", Category: "send", Amount: 1.5, Fee: dcrjson.Float64(0.0001), Confirmations: 1, TxID: "456", WalletConflicts: []string{}, Time: 12345678, TimeReceived: 12345876, Vout: 789, OtherAccount: "otheracct", }, }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the notification as created by the new static // creation function. The ID is nil for notifications. marshalled, err := dcrjson.MarshalCmd(nil, test.staticNtfn()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the notification is created without error via the // generic new notification creation function. cmd, err := test.newNtfn() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the notification as created by the generic new // notification creation function. The ID is nil for // notifications. marshalled, err = dcrjson.MarshalCmd(nil, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands // marshal and unmarshal into valid results include handling of optional fields // being omitted in the marshalled command, while optional fields with defaults // have the default assigned on unmarshalled commands. func TestChainSvrWsCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "authenticate", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("authenticate", "user", "pass") }, staticCmd: func() interface{} { return dcrjson.NewAuthenticateCmd("user", "pass") }, marshalled: `{"jsonrpc":"1.0","method":"authenticate","params":["user","pass"],"id":1}`, unmarshalled: &dcrjson.AuthenticateCmd{Username: "******", Passphrase: "pass"}, }, { name: "notifyblocks", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifyblocks") }, staticCmd: func() interface{} { return dcrjson.NewNotifyBlocksCmd() }, marshalled: `{"jsonrpc":"1.0","method":"notifyblocks","params":[],"id":1}`, unmarshalled: &dcrjson.NotifyBlocksCmd{}, }, { name: "stopnotifyblocks", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("stopnotifyblocks") }, staticCmd: func() interface{} { return dcrjson.NewStopNotifyBlocksCmd() }, marshalled: `{"jsonrpc":"1.0","method":"stopnotifyblocks","params":[],"id":1}`, unmarshalled: &dcrjson.StopNotifyBlocksCmd{}, }, { name: "notifynewtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifynewtransactions") }, staticCmd: func() interface{} { return dcrjson.NewNotifyNewTransactionsCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"notifynewtransactions","params":[],"id":1}`, unmarshalled: &dcrjson.NotifyNewTransactionsCmd{ Verbose: dcrjson.Bool(false), }, }, { name: "notifynewtransactions optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("notifynewtransactions", true) }, staticCmd: func() interface{} { return dcrjson.NewNotifyNewTransactionsCmd(dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"notifynewtransactions","params":[true],"id":1}`, unmarshalled: &dcrjson.NotifyNewTransactionsCmd{ Verbose: dcrjson.Bool(true), }, }, { name: "stopnotifynewtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("stopnotifynewtransactions") }, staticCmd: func() interface{} { return dcrjson.NewStopNotifyNewTransactionsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"stopnotifynewtransactions","params":[],"id":1}`, unmarshalled: &dcrjson.StopNotifyNewTransactionsCmd{}, }, { name: "rescan", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("rescan", "0000000000000000000000000000000000000000000000000000000000000123") }, staticCmd: func() interface{} { return dcrjson.NewRescanCmd("0000000000000000000000000000000000000000000000000000000000000123") }, marshalled: `{"jsonrpc":"1.0","method":"rescan","params":["0000000000000000000000000000000000000000000000000000000000000123"],"id":1}`, unmarshalled: &dcrjson.RescanCmd{ BlockHashes: "0000000000000000000000000000000000000000000000000000000000000123", }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestWalletSvrCmds tests all of the wallet server commands marshal and // unmarshal into valid results include handling of optional fields being // omitted in the marshalled command, while optional fields with defaults have // the default assigned on unmarshalled commands. func TestWalletSvrCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "addmultisigaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("addmultisigaddress", 2, []string{"031234", "035678"}) }, staticCmd: func() interface{} { keys := []string{"031234", "035678"} return dcrjson.NewAddMultisigAddressCmd(2, keys, nil) }, marshalled: `{"jsonrpc":"1.0","method":"addmultisigaddress","params":[2,["031234","035678"]],"id":1}`, unmarshalled: &dcrjson.AddMultisigAddressCmd{ NRequired: 2, Keys: []string{"031234", "035678"}, Account: nil, }, }, { name: "addmultisigaddress optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("addmultisigaddress", 2, []string{"031234", "035678"}, "test") }, staticCmd: func() interface{} { keys := []string{"031234", "035678"} return dcrjson.NewAddMultisigAddressCmd(2, keys, dcrjson.String("test")) }, marshalled: `{"jsonrpc":"1.0","method":"addmultisigaddress","params":[2,["031234","035678"],"test"],"id":1}`, unmarshalled: &dcrjson.AddMultisigAddressCmd{ NRequired: 2, Keys: []string{"031234", "035678"}, Account: dcrjson.String("test"), }, }, { name: "createmultisig", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("createmultisig", 2, []string{"031234", "035678"}) }, staticCmd: func() interface{} { keys := []string{"031234", "035678"} return dcrjson.NewCreateMultisigCmd(2, keys) }, marshalled: `{"jsonrpc":"1.0","method":"createmultisig","params":[2,["031234","035678"]],"id":1}`, unmarshalled: &dcrjson.CreateMultisigCmd{ NRequired: 2, Keys: []string{"031234", "035678"}, }, }, { name: "dumpprivkey", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("dumpprivkey", "1Address") }, staticCmd: func() interface{} { return dcrjson.NewDumpPrivKeyCmd("1Address") }, marshalled: `{"jsonrpc":"1.0","method":"dumpprivkey","params":["1Address"],"id":1}`, unmarshalled: &dcrjson.DumpPrivKeyCmd{ Address: "1Address", }, }, { name: "encryptwallet", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("encryptwallet", "pass") }, staticCmd: func() interface{} { return dcrjson.NewEncryptWalletCmd("pass") }, marshalled: `{"jsonrpc":"1.0","method":"encryptwallet","params":["pass"],"id":1}`, unmarshalled: &dcrjson.EncryptWalletCmd{ Passphrase: "pass", }, }, { name: "estimatefee", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("estimatefee", 6) }, staticCmd: func() interface{} { return dcrjson.NewEstimateFeeCmd(6) }, marshalled: `{"jsonrpc":"1.0","method":"estimatefee","params":[6],"id":1}`, unmarshalled: &dcrjson.EstimateFeeCmd{ NumBlocks: 6, }, }, { name: "estimatepriority", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("estimatepriority", 6) }, staticCmd: func() interface{} { return dcrjson.NewEstimatePriorityCmd(6) }, marshalled: `{"jsonrpc":"1.0","method":"estimatepriority","params":[6],"id":1}`, unmarshalled: &dcrjson.EstimatePriorityCmd{ NumBlocks: 6, }, }, { name: "getaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getaccount", "1Address") }, staticCmd: func() interface{} { return dcrjson.NewGetAccountCmd("1Address") }, marshalled: `{"jsonrpc":"1.0","method":"getaccount","params":["1Address"],"id":1}`, unmarshalled: &dcrjson.GetAccountCmd{ Address: "1Address", }, }, { name: "getaccountaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getaccountaddress", "acct") }, staticCmd: func() interface{} { return dcrjson.NewGetAccountAddressCmd("acct") }, marshalled: `{"jsonrpc":"1.0","method":"getaccountaddress","params":["acct"],"id":1}`, unmarshalled: &dcrjson.GetAccountAddressCmd{ Account: "acct", }, }, { name: "getaddressesbyaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getaddressesbyaccount", "acct") }, staticCmd: func() interface{} { return dcrjson.NewGetAddressesByAccountCmd("acct") }, marshalled: `{"jsonrpc":"1.0","method":"getaddressesbyaccount","params":["acct"],"id":1}`, unmarshalled: &dcrjson.GetAddressesByAccountCmd{ Account: "acct", }, }, { name: "getbalance", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getbalance") }, staticCmd: func() interface{} { return dcrjson.NewGetBalanceCmd(nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getbalance","params":[],"id":1}`, unmarshalled: &dcrjson.GetBalanceCmd{ Account: nil, MinConf: dcrjson.Int(1), }, }, { name: "getbalance optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getbalance", "acct") }, staticCmd: func() interface{} { return dcrjson.NewGetBalanceCmd(dcrjson.String("acct"), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getbalance","params":["acct"],"id":1}`, unmarshalled: &dcrjson.GetBalanceCmd{ Account: dcrjson.String("acct"), MinConf: dcrjson.Int(1), }, }, { name: "getbalance optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getbalance", "acct", 6) }, staticCmd: func() interface{} { return dcrjson.NewGetBalanceCmd(dcrjson.String("acct"), dcrjson.Int(6), nil) }, marshalled: `{"jsonrpc":"1.0","method":"getbalance","params":["acct",6],"id":1}`, unmarshalled: &dcrjson.GetBalanceCmd{ Account: dcrjson.String("acct"), MinConf: dcrjson.Int(6), }, }, { name: "getnewaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnewaddress") }, staticCmd: func() interface{} { return dcrjson.NewGetNewAddressCmd(nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getnewaddress","params":[],"id":1}`, unmarshalled: &dcrjson.GetNewAddressCmd{ Account: nil, Verbose: dcrjson.Bool(false), }, }, { name: "getnewaddress optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getnewaddress", "acct", "true") }, staticCmd: func() interface{} { return dcrjson.NewGetNewAddressCmd(dcrjson.String("acct"), dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"getnewaddress","params":["acct",true],"id":1}`, unmarshalled: &dcrjson.GetNewAddressCmd{ Account: dcrjson.String("acct"), Verbose: dcrjson.Bool(true), }, }, { name: "getrawchangeaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawchangeaddress") }, staticCmd: func() interface{} { return dcrjson.NewGetRawChangeAddressCmd(nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"getrawchangeaddress","params":[],"id":1}`, unmarshalled: &dcrjson.GetRawChangeAddressCmd{ Account: nil, Verbose: dcrjson.Bool(false), }, }, { name: "getrawchangeaddress optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getrawchangeaddress", "acct", "true") }, staticCmd: func() interface{} { return dcrjson.NewGetRawChangeAddressCmd(dcrjson.String("acct"), dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"getrawchangeaddress","params":["acct",true],"id":1}`, unmarshalled: &dcrjson.GetRawChangeAddressCmd{ Account: dcrjson.String("acct"), Verbose: dcrjson.Bool(true), }, }, { name: "getreceivedbyaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getreceivedbyaccount", "acct") }, staticCmd: func() interface{} { return dcrjson.NewGetReceivedByAccountCmd("acct", nil) }, marshalled: `{"jsonrpc":"1.0","method":"getreceivedbyaccount","params":["acct"],"id":1}`, unmarshalled: &dcrjson.GetReceivedByAccountCmd{ Account: "acct", MinConf: dcrjson.Int(1), }, }, { name: "getreceivedbyaccount optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getreceivedbyaccount", "acct", 6) }, staticCmd: func() interface{} { return dcrjson.NewGetReceivedByAccountCmd("acct", dcrjson.Int(6)) }, marshalled: `{"jsonrpc":"1.0","method":"getreceivedbyaccount","params":["acct",6],"id":1}`, unmarshalled: &dcrjson.GetReceivedByAccountCmd{ Account: "acct", MinConf: dcrjson.Int(6), }, }, { name: "getreceivedbyaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getreceivedbyaddress", "1Address") }, staticCmd: func() interface{} { return dcrjson.NewGetReceivedByAddressCmd("1Address", nil) }, marshalled: `{"jsonrpc":"1.0","method":"getreceivedbyaddress","params":["1Address"],"id":1}`, unmarshalled: &dcrjson.GetReceivedByAddressCmd{ Address: "1Address", MinConf: dcrjson.Int(1), }, }, { name: "getreceivedbyaddress optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getreceivedbyaddress", "1Address", 6) }, staticCmd: func() interface{} { return dcrjson.NewGetReceivedByAddressCmd("1Address", dcrjson.Int(6)) }, marshalled: `{"jsonrpc":"1.0","method":"getreceivedbyaddress","params":["1Address",6],"id":1}`, unmarshalled: &dcrjson.GetReceivedByAddressCmd{ Address: "1Address", MinConf: dcrjson.Int(6), }, }, { name: "gettransaction", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettransaction", "123") }, staticCmd: func() interface{} { return dcrjson.NewGetTransactionCmd("123", nil) }, marshalled: `{"jsonrpc":"1.0","method":"gettransaction","params":["123"],"id":1}`, unmarshalled: &dcrjson.GetTransactionCmd{ Txid: "123", IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "gettransaction optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("gettransaction", "123", true) }, staticCmd: func() interface{} { return dcrjson.NewGetTransactionCmd("123", dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"gettransaction","params":["123",true],"id":1}`, unmarshalled: &dcrjson.GetTransactionCmd{ Txid: "123", IncludeWatchOnly: dcrjson.Bool(true), }, }, { name: "importprivkey", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importprivkey", "abc") }, staticCmd: func() interface{} { return dcrjson.NewImportPrivKeyCmd("abc", nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"importprivkey","params":["abc"],"id":1}`, unmarshalled: &dcrjson.ImportPrivKeyCmd{ PrivKey: "abc", Label: nil, Rescan: dcrjson.Bool(true), }, }, { name: "importprivkey optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importprivkey", "abc", "label") }, staticCmd: func() interface{} { return dcrjson.NewImportPrivKeyCmd("abc", dcrjson.String("label"), nil) }, marshalled: `{"jsonrpc":"1.0","method":"importprivkey","params":["abc","label"],"id":1}`, unmarshalled: &dcrjson.ImportPrivKeyCmd{ PrivKey: "abc", Label: dcrjson.String("label"), Rescan: dcrjson.Bool(true), }, }, { name: "importprivkey optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("importprivkey", "abc", "label", false) }, staticCmd: func() interface{} { return dcrjson.NewImportPrivKeyCmd("abc", dcrjson.String("label"), dcrjson.Bool(false)) }, marshalled: `{"jsonrpc":"1.0","method":"importprivkey","params":["abc","label",false],"id":1}`, unmarshalled: &dcrjson.ImportPrivKeyCmd{ PrivKey: "abc", Label: dcrjson.String("label"), Rescan: dcrjson.Bool(false), }, }, { name: "keypoolrefill", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("keypoolrefill") }, staticCmd: func() interface{} { return dcrjson.NewKeyPoolRefillCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"keypoolrefill","params":[],"id":1}`, unmarshalled: &dcrjson.KeyPoolRefillCmd{ NewSize: dcrjson.Uint(100), }, }, { name: "keypoolrefill optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("keypoolrefill", 200) }, staticCmd: func() interface{} { return dcrjson.NewKeyPoolRefillCmd(dcrjson.Uint(200)) }, marshalled: `{"jsonrpc":"1.0","method":"keypoolrefill","params":[200],"id":1}`, unmarshalled: &dcrjson.KeyPoolRefillCmd{ NewSize: dcrjson.Uint(200), }, }, { name: "listaccounts", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listaccounts") }, staticCmd: func() interface{} { return dcrjson.NewListAccountsCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"listaccounts","params":[],"id":1}`, unmarshalled: &dcrjson.ListAccountsCmd{ MinConf: dcrjson.Int(1), }, }, { name: "listaccounts optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listaccounts", 6) }, staticCmd: func() interface{} { return dcrjson.NewListAccountsCmd(dcrjson.Int(6)) }, marshalled: `{"jsonrpc":"1.0","method":"listaccounts","params":[6],"id":1}`, unmarshalled: &dcrjson.ListAccountsCmd{ MinConf: dcrjson.Int(6), }, }, { name: "listaddressgroupings", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listaddressgroupings") }, staticCmd: func() interface{} { return dcrjson.NewListAddressGroupingsCmd() }, marshalled: `{"jsonrpc":"1.0","method":"listaddressgroupings","params":[],"id":1}`, unmarshalled: &dcrjson.ListAddressGroupingsCmd{}, }, { name: "listlockunspent", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listlockunspent") }, staticCmd: func() interface{} { return dcrjson.NewListLockUnspentCmd() }, marshalled: `{"jsonrpc":"1.0","method":"listlockunspent","params":[],"id":1}`, unmarshalled: &dcrjson.ListLockUnspentCmd{}, }, { name: "listreceivedbyaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaccount") }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAccountCmd(nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaccount","params":[],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAccountCmd{ MinConf: dcrjson.Int(1), IncludeEmpty: dcrjson.Bool(false), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaccount optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaccount", 6) }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAccountCmd(dcrjson.Int(6), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaccount","params":[6],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAccountCmd{ MinConf: dcrjson.Int(6), IncludeEmpty: dcrjson.Bool(false), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaccount optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaccount", 6, true) }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAccountCmd(dcrjson.Int(6), dcrjson.Bool(true), nil) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaccount","params":[6,true],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAccountCmd{ MinConf: dcrjson.Int(6), IncludeEmpty: dcrjson.Bool(true), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaccount optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaccount", 6, true, false) }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAccountCmd(dcrjson.Int(6), dcrjson.Bool(true), dcrjson.Bool(false)) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaccount","params":[6,true,false],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAccountCmd{ MinConf: dcrjson.Int(6), IncludeEmpty: dcrjson.Bool(true), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaddress") }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAddressCmd(nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaddress","params":[],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAddressCmd{ MinConf: dcrjson.Int(1), IncludeEmpty: dcrjson.Bool(false), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaddress optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaddress", 6) }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAddressCmd(dcrjson.Int(6), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaddress","params":[6],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAddressCmd{ MinConf: dcrjson.Int(6), IncludeEmpty: dcrjson.Bool(false), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaddress optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaddress", 6, true) }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAddressCmd(dcrjson.Int(6), dcrjson.Bool(true), nil) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaddress","params":[6,true],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAddressCmd{ MinConf: dcrjson.Int(6), IncludeEmpty: dcrjson.Bool(true), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listreceivedbyaddress optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listreceivedbyaddress", 6, true, false) }, staticCmd: func() interface{} { return dcrjson.NewListReceivedByAddressCmd(dcrjson.Int(6), dcrjson.Bool(true), dcrjson.Bool(false)) }, marshalled: `{"jsonrpc":"1.0","method":"listreceivedbyaddress","params":[6,true,false],"id":1}`, unmarshalled: &dcrjson.ListReceivedByAddressCmd{ MinConf: dcrjson.Int(6), IncludeEmpty: dcrjson.Bool(true), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listsinceblock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listsinceblock") }, staticCmd: func() interface{} { return dcrjson.NewListSinceBlockCmd(nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listsinceblock","params":[],"id":1}`, unmarshalled: &dcrjson.ListSinceBlockCmd{ BlockHash: nil, TargetConfirmations: dcrjson.Int(1), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listsinceblock optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listsinceblock", "123") }, staticCmd: func() interface{} { return dcrjson.NewListSinceBlockCmd(dcrjson.String("123"), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listsinceblock","params":["123"],"id":1}`, unmarshalled: &dcrjson.ListSinceBlockCmd{ BlockHash: dcrjson.String("123"), TargetConfirmations: dcrjson.Int(1), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listsinceblock optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listsinceblock", "123", 6) }, staticCmd: func() interface{} { return dcrjson.NewListSinceBlockCmd(dcrjson.String("123"), dcrjson.Int(6), nil) }, marshalled: `{"jsonrpc":"1.0","method":"listsinceblock","params":["123",6],"id":1}`, unmarshalled: &dcrjson.ListSinceBlockCmd{ BlockHash: dcrjson.String("123"), TargetConfirmations: dcrjson.Int(6), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listsinceblock optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listsinceblock", "123", 6, true) }, staticCmd: func() interface{} { return dcrjson.NewListSinceBlockCmd(dcrjson.String("123"), dcrjson.Int(6), dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"listsinceblock","params":["123",6,true],"id":1}`, unmarshalled: &dcrjson.ListSinceBlockCmd{ BlockHash: dcrjson.String("123"), TargetConfirmations: dcrjson.Int(6), IncludeWatchOnly: dcrjson.Bool(true), }, }, { name: "listtransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listtransactions") }, staticCmd: func() interface{} { return dcrjson.NewListTransactionsCmd(nil, nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listtransactions","params":[],"id":1}`, unmarshalled: &dcrjson.ListTransactionsCmd{ Account: nil, Count: dcrjson.Int(10), From: dcrjson.Int(0), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listtransactions optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listtransactions", "acct") }, staticCmd: func() interface{} { return dcrjson.NewListTransactionsCmd(dcrjson.String("acct"), nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listtransactions","params":["acct"],"id":1}`, unmarshalled: &dcrjson.ListTransactionsCmd{ Account: dcrjson.String("acct"), Count: dcrjson.Int(10), From: dcrjson.Int(0), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listtransactions optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listtransactions", "acct", 20) }, staticCmd: func() interface{} { return dcrjson.NewListTransactionsCmd(dcrjson.String("acct"), dcrjson.Int(20), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listtransactions","params":["acct",20],"id":1}`, unmarshalled: &dcrjson.ListTransactionsCmd{ Account: dcrjson.String("acct"), Count: dcrjson.Int(20), From: dcrjson.Int(0), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listtransactions optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listtransactions", "acct", 20, 1) }, staticCmd: func() interface{} { return dcrjson.NewListTransactionsCmd(dcrjson.String("acct"), dcrjson.Int(20), dcrjson.Int(1), nil) }, marshalled: `{"jsonrpc":"1.0","method":"listtransactions","params":["acct",20,1],"id":1}`, unmarshalled: &dcrjson.ListTransactionsCmd{ Account: dcrjson.String("acct"), Count: dcrjson.Int(20), From: dcrjson.Int(1), IncludeWatchOnly: dcrjson.Bool(false), }, }, { name: "listtransactions optional4", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listtransactions", "acct", 20, 1, true) }, staticCmd: func() interface{} { return dcrjson.NewListTransactionsCmd(dcrjson.String("acct"), dcrjson.Int(20), dcrjson.Int(1), dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"listtransactions","params":["acct",20,1,true],"id":1}`, unmarshalled: &dcrjson.ListTransactionsCmd{ Account: dcrjson.String("acct"), Count: dcrjson.Int(20), From: dcrjson.Int(1), IncludeWatchOnly: dcrjson.Bool(true), }, }, { name: "listunspent", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listunspent") }, staticCmd: func() interface{} { return dcrjson.NewListUnspentCmd(nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listunspent","params":[],"id":1}`, unmarshalled: &dcrjson.ListUnspentCmd{ MinConf: dcrjson.Int(1), MaxConf: dcrjson.Int(9999999), Addresses: nil, }, }, { name: "listunspent optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listunspent", 6) }, staticCmd: func() interface{} { return dcrjson.NewListUnspentCmd(dcrjson.Int(6), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listunspent","params":[6],"id":1}`, unmarshalled: &dcrjson.ListUnspentCmd{ MinConf: dcrjson.Int(6), MaxConf: dcrjson.Int(9999999), Addresses: nil, }, }, { name: "listunspent optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listunspent", 6, 100) }, staticCmd: func() interface{} { return dcrjson.NewListUnspentCmd(dcrjson.Int(6), dcrjson.Int(100), nil) }, marshalled: `{"jsonrpc":"1.0","method":"listunspent","params":[6,100],"id":1}`, unmarshalled: &dcrjson.ListUnspentCmd{ MinConf: dcrjson.Int(6), MaxConf: dcrjson.Int(100), Addresses: nil, }, }, { name: "listunspent optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listunspent", 6, 100, []string{"1Address", "1Address2"}) }, staticCmd: func() interface{} { return dcrjson.NewListUnspentCmd(dcrjson.Int(6), dcrjson.Int(100), &[]string{"1Address", "1Address2"}) }, marshalled: `{"jsonrpc":"1.0","method":"listunspent","params":[6,100,["1Address","1Address2"]],"id":1}`, unmarshalled: &dcrjson.ListUnspentCmd{ MinConf: dcrjson.Int(6), MaxConf: dcrjson.Int(100), Addresses: &[]string{"1Address", "1Address2"}, }, }, { name: "lockunspent", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("lockunspent", true, `[{"txid":"123","vout":1}]`) }, staticCmd: func() interface{} { txInputs := []dcrjson.TransactionInput{ {Txid: "123", Vout: 1}, } return dcrjson.NewLockUnspentCmd(true, txInputs) }, marshalled: `{"jsonrpc":"1.0","method":"lockunspent","params":[true,[{"txid":"123","vout":1,"tree":0}]],"id":1}`, unmarshalled: &dcrjson.LockUnspentCmd{ Unlock: true, Transactions: []dcrjson.TransactionInput{ {Txid: "123", Vout: 1}, }, }, }, { name: "move", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("move", "from", "to", 0.5) }, staticCmd: func() interface{} { return dcrjson.NewMoveCmd("from", "to", 0.5, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"move","params":["from","to",0.5],"id":1}`, unmarshalled: &dcrjson.MoveCmd{ FromAccount: "from", ToAccount: "to", Amount: 0.5, MinConf: dcrjson.Int(1), Comment: nil, }, }, { name: "move optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("move", "from", "to", 0.5, 6) }, staticCmd: func() interface{} { return dcrjson.NewMoveCmd("from", "to", 0.5, dcrjson.Int(6), nil) }, marshalled: `{"jsonrpc":"1.0","method":"move","params":["from","to",0.5,6],"id":1}`, unmarshalled: &dcrjson.MoveCmd{ FromAccount: "from", ToAccount: "to", Amount: 0.5, MinConf: dcrjson.Int(6), Comment: nil, }, }, { name: "move optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("move", "from", "to", 0.5, 6, "comment") }, staticCmd: func() interface{} { return dcrjson.NewMoveCmd("from", "to", 0.5, dcrjson.Int(6), dcrjson.String("comment")) }, marshalled: `{"jsonrpc":"1.0","method":"move","params":["from","to",0.5,6,"comment"],"id":1}`, unmarshalled: &dcrjson.MoveCmd{ FromAccount: "from", ToAccount: "to", Amount: 0.5, MinConf: dcrjson.Int(6), Comment: dcrjson.String("comment"), }, }, { name: "sendfrom", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendfrom", "from", "1Address", 0.5) }, staticCmd: func() interface{} { return dcrjson.NewSendFromCmd("from", "1Address", 0.5, nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5],"id":1}`, unmarshalled: &dcrjson.SendFromCmd{ FromAccount: "from", ToAddress: "1Address", Amount: 0.5, MinConf: dcrjson.Int(1), Comment: nil, CommentTo: nil, }, }, { name: "sendfrom optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6) }, staticCmd: func() interface{} { return dcrjson.NewSendFromCmd("from", "1Address", 0.5, dcrjson.Int(6), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6],"id":1}`, unmarshalled: &dcrjson.SendFromCmd{ FromAccount: "from", ToAddress: "1Address", Amount: 0.5, MinConf: dcrjson.Int(6), Comment: nil, CommentTo: nil, }, }, { name: "sendfrom optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "comment") }, staticCmd: func() interface{} { return dcrjson.NewSendFromCmd("from", "1Address", 0.5, dcrjson.Int(6), dcrjson.String("comment"), nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"comment"],"id":1}`, unmarshalled: &dcrjson.SendFromCmd{ FromAccount: "from", ToAddress: "1Address", Amount: 0.5, MinConf: dcrjson.Int(6), Comment: dcrjson.String("comment"), CommentTo: nil, }, }, { name: "sendfrom optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "comment", "commentto") }, staticCmd: func() interface{} { return dcrjson.NewSendFromCmd("from", "1Address", 0.5, dcrjson.Int(6), dcrjson.String("comment"), dcrjson.String("commentto")) }, marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"comment","commentto"],"id":1}`, unmarshalled: &dcrjson.SendFromCmd{ FromAccount: "from", ToAddress: "1Address", Amount: 0.5, MinConf: dcrjson.Int(6), Comment: dcrjson.String("comment"), CommentTo: dcrjson.String("commentto"), }, }, { name: "sendmany", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendmany", "from", `{"1Address":0.5}`) }, staticCmd: func() interface{} { amounts := map[string]float64{"1Address": 0.5} return dcrjson.NewSendManyCmd("from", amounts, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5}],"id":1}`, unmarshalled: &dcrjson.SendManyCmd{ FromAccount: "from", Amounts: map[string]float64{"1Address": 0.5}, MinConf: dcrjson.Int(1), Comment: nil, }, }, { name: "sendmany optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendmany", "from", `{"1Address":0.5}`, 6) }, staticCmd: func() interface{} { amounts := map[string]float64{"1Address": 0.5} return dcrjson.NewSendManyCmd("from", amounts, dcrjson.Int(6), nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5},6],"id":1}`, unmarshalled: &dcrjson.SendManyCmd{ FromAccount: "from", Amounts: map[string]float64{"1Address": 0.5}, MinConf: dcrjson.Int(6), Comment: nil, }, }, { name: "sendmany optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendmany", "from", `{"1Address":0.5}`, 6, "comment") }, staticCmd: func() interface{} { amounts := map[string]float64{"1Address": 0.5} return dcrjson.NewSendManyCmd("from", amounts, dcrjson.Int(6), dcrjson.String("comment")) }, marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5},6,"comment"],"id":1}`, unmarshalled: &dcrjson.SendManyCmd{ FromAccount: "from", Amounts: map[string]float64{"1Address": 0.5}, MinConf: dcrjson.Int(6), Comment: dcrjson.String("comment"), }, }, { name: "sendtoaddress", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendtoaddress", "1Address", 0.5) }, staticCmd: func() interface{} { return dcrjson.NewSendToAddressCmd("1Address", 0.5, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendtoaddress","params":["1Address",0.5],"id":1}`, unmarshalled: &dcrjson.SendToAddressCmd{ Address: "1Address", Amount: 0.5, Comment: nil, CommentTo: nil, }, }, { name: "sendtoaddress optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("sendtoaddress", "1Address", 0.5, "comment", "commentto") }, staticCmd: func() interface{} { return dcrjson.NewSendToAddressCmd("1Address", 0.5, dcrjson.String("comment"), dcrjson.String("commentto")) }, marshalled: `{"jsonrpc":"1.0","method":"sendtoaddress","params":["1Address",0.5,"comment","commentto"],"id":1}`, unmarshalled: &dcrjson.SendToAddressCmd{ Address: "1Address", Amount: 0.5, Comment: dcrjson.String("comment"), CommentTo: dcrjson.String("commentto"), }, }, { name: "setaccount", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("setaccount", "1Address", "acct") }, staticCmd: func() interface{} { return dcrjson.NewSetAccountCmd("1Address", "acct") }, marshalled: `{"jsonrpc":"1.0","method":"setaccount","params":["1Address","acct"],"id":1}`, unmarshalled: &dcrjson.SetAccountCmd{ Address: "1Address", Account: "acct", }, }, { name: "settxfee", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("settxfee", 0.0001) }, staticCmd: func() interface{} { return dcrjson.NewSetTxFeeCmd(0.0001) }, marshalled: `{"jsonrpc":"1.0","method":"settxfee","params":[0.0001],"id":1}`, unmarshalled: &dcrjson.SetTxFeeCmd{ Amount: 0.0001, }, }, { name: "signmessage", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("signmessage", "1Address", "message") }, staticCmd: func() interface{} { return dcrjson.NewSignMessageCmd("1Address", "message") }, marshalled: `{"jsonrpc":"1.0","method":"signmessage","params":["1Address","message"],"id":1}`, unmarshalled: &dcrjson.SignMessageCmd{ Address: "1Address", Message: "message", }, }, { name: "signrawtransaction", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("signrawtransaction", "001122") }, staticCmd: func() interface{} { return dcrjson.NewSignRawTransactionCmd("001122", nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"signrawtransaction","params":["001122"],"id":1}`, unmarshalled: &dcrjson.SignRawTransactionCmd{ RawTx: "001122", Inputs: nil, PrivKeys: nil, Flags: dcrjson.String("ALL"), }, }, { name: "signrawtransaction optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("signrawtransaction", "001122", `[{"txid":"123","vout":1,"tree":0,"scriptPubKey":"00","redeemScript":"01"}]`) }, staticCmd: func() interface{} { txInputs := []dcrjson.RawTxInput{ { Txid: "123", Vout: 1, ScriptPubKey: "00", RedeemScript: "01", }, } return dcrjson.NewSignRawTransactionCmd("001122", &txInputs, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"signrawtransaction","params":["001122",[{"txid":"123","vout":1,"tree":0,"scriptPubKey":"00","redeemScript":"01"}]],"id":1}`, unmarshalled: &dcrjson.SignRawTransactionCmd{ RawTx: "001122", Inputs: &[]dcrjson.RawTxInput{ { Txid: "123", Vout: 1, ScriptPubKey: "00", RedeemScript: "01", }, }, PrivKeys: nil, Flags: dcrjson.String("ALL"), }, }, { name: "signrawtransaction optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("signrawtransaction", "001122", `[]`, `["abc"]`) }, staticCmd: func() interface{} { txInputs := []dcrjson.RawTxInput{} privKeys := []string{"abc"} return dcrjson.NewSignRawTransactionCmd("001122", &txInputs, &privKeys, nil) }, marshalled: `{"jsonrpc":"1.0","method":"signrawtransaction","params":["001122",[],["abc"]],"id":1}`, unmarshalled: &dcrjson.SignRawTransactionCmd{ RawTx: "001122", Inputs: &[]dcrjson.RawTxInput{}, PrivKeys: &[]string{"abc"}, Flags: dcrjson.String("ALL"), }, }, { name: "signrawtransaction optional3", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("signrawtransaction", "001122", `[]`, `[]`, "ALL") }, staticCmd: func() interface{} { txInputs := []dcrjson.RawTxInput{} privKeys := []string{} return dcrjson.NewSignRawTransactionCmd("001122", &txInputs, &privKeys, dcrjson.String("ALL")) }, marshalled: `{"jsonrpc":"1.0","method":"signrawtransaction","params":["001122",[],[],"ALL"],"id":1}`, unmarshalled: &dcrjson.SignRawTransactionCmd{ RawTx: "001122", Inputs: &[]dcrjson.RawTxInput{}, PrivKeys: &[]string{}, Flags: dcrjson.String("ALL"), }, }, { name: "walletlock", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("walletlock") }, staticCmd: func() interface{} { return dcrjson.NewWalletLockCmd() }, marshalled: `{"jsonrpc":"1.0","method":"walletlock","params":[],"id":1}`, unmarshalled: &dcrjson.WalletLockCmd{}, }, { name: "walletpassphrase", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("walletpassphrase", "pass", 60) }, staticCmd: func() interface{} { return dcrjson.NewWalletPassphraseCmd("pass", 60) }, marshalled: `{"jsonrpc":"1.0","method":"walletpassphrase","params":["pass",60],"id":1}`, unmarshalled: &dcrjson.WalletPassphraseCmd{ Passphrase: "pass", Timeout: 60, }, }, { name: "walletpassphrasechange", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("walletpassphrasechange", "old", "new") }, staticCmd: func() interface{} { return dcrjson.NewWalletPassphraseChangeCmd("old", "new") }, marshalled: `{"jsonrpc":"1.0","method":"walletpassphrasechange","params":["old","new"],"id":1}`, unmarshalled: &dcrjson.WalletPassphraseChangeCmd{ OldPassphrase: "old", NewPassphrase: "new", }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
func main() { cfg, args, err := loadConfig() if err != nil { os.Exit(1) } if cfg.Terminal { startTerminal(cfg) os.Exit(1) } if len(args) < 1 { usage("No command specified") os.Exit(1) } // Ensure the specified method identifies a valid registered command and // is one of the usable types. method := args[0] usageFlags, err := dcrjson.MethodUsageFlags(method) if err != nil { fmt.Fprintf(os.Stderr, "Unrecognized command '%s'\n", method) fmt.Fprintln(os.Stderr, listCmdMessage) os.Exit(1) } if usageFlags&unusableFlags != 0 { fmt.Fprintf(os.Stderr, "The '%s' command can only be used via "+ "websockets\n", method) fmt.Fprintln(os.Stderr, listCmdMessage) os.Exit(1) } // Convert remaining command line args to a slice of interface values // to be passed along as parameters to new command creation function. // // Since some commands, such as submitblock, can involve data which is // too large for the Operating System to allow as a normal command line // parameter, support using '-' as an argument to allow the argument // to be read from a stdin pipe. bio := bufio.NewReader(os.Stdin) params := make([]interface{}, 0, len(args[1:])) for _, arg := range args[1:] { if arg == "-" { param, err := bio.ReadString('\n') if err != nil && err != io.EOF { fmt.Fprintf(os.Stderr, "Failed to read data "+ "from stdin: %v\n", err) os.Exit(1) } if err == io.EOF && len(param) == 0 { fmt.Fprintln(os.Stderr, "Not enough lines "+ "provided on stdin") os.Exit(1) } param = strings.TrimRight(param, "\r\n") params = append(params, param) continue } params = append(params, arg) } // Attempt to create the appropriate command using the arguments // provided by the user. cmd, err := dcrjson.NewCmd(method, params...) if err != nil { // Show the error along with its error code when it's a // dcrjson.Error as it reallistcally will always be since the // NewCmd function is only supposed to return errors of that // type. if jerr, ok := err.(dcrjson.Error); ok { fmt.Fprintf(os.Stderr, "%s command: %v (code: %s)\n", method, err, jerr.Code) commandUsage(method) os.Exit(1) } // The error is not a dcrjson.Error and this really should not // happen. Nevertheless, fallback to just showing the error // if it should happen due to a bug in the package. fmt.Fprintf(os.Stderr, "%s command: %v\n", method, err) commandUsage(method) os.Exit(1) } // Marshal the command into a JSON-RPC byte slice in preparation for // sending it to the RPC server. marshalledJSON, err := dcrjson.MarshalCmd(1, cmd) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // Send the JSON-RPC request to the server using the user-specified // connection configuration. result, err := sendPostRequest(marshalledJSON, cfg) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // Choose how to display the result based on its type. strResult := string(result) if strings.HasPrefix(strResult, "{") || strings.HasPrefix(strResult, "[") { var dst bytes.Buffer if err := json.Indent(&dst, result, "", " "); err != nil { fmt.Fprintf(os.Stderr, "Failed to format result: %v", err) os.Exit(1) } fmt.Println(dst.String()) } else if strings.HasPrefix(strResult, `"`) { var str string if err := json.Unmarshal(result, &str); err != nil { fmt.Fprintf(os.Stderr, "Failed to unmarshal result: %v", err) os.Exit(1) } fmt.Println(str) } else if strResult != "null" { fmt.Println(strResult) } }
// TestWalletSvrWsCmds tests all of the wallet server websocket-specific // commands marshal and unmarshal into valid results include handling of // optional fields being omitted in the marshalled command, while optional // fields with defaults have the default assigned on unmarshalled commands. func TestWalletSvrWsCmds(t *testing.T) { t.Parallel() testID := int(1) tests := []struct { name string newCmd func() (interface{}, error) staticCmd func() interface{} marshalled string unmarshalled interface{} }{ { name: "createencryptedwallet", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("createencryptedwallet", "pass") }, staticCmd: func() interface{} { return dcrjson.NewCreateEncryptedWalletCmd("pass") }, marshalled: `{"jsonrpc":"1.0","method":"createencryptedwallet","params":["pass"],"id":1}`, unmarshalled: &dcrjson.CreateEncryptedWalletCmd{Passphrase: "pass"}, }, { name: "exportwatchingwallet", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("exportwatchingwallet") }, staticCmd: func() interface{} { return dcrjson.NewExportWatchingWalletCmd(nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"exportwatchingwallet","params":[],"id":1}`, unmarshalled: &dcrjson.ExportWatchingWalletCmd{ Account: nil, Download: dcrjson.Bool(false), }, }, { name: "exportwatchingwallet optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("exportwatchingwallet", "acct") }, staticCmd: func() interface{} { return dcrjson.NewExportWatchingWalletCmd(dcrjson.String("acct"), nil) }, marshalled: `{"jsonrpc":"1.0","method":"exportwatchingwallet","params":["acct"],"id":1}`, unmarshalled: &dcrjson.ExportWatchingWalletCmd{ Account: dcrjson.String("acct"), Download: dcrjson.Bool(false), }, }, { name: "exportwatchingwallet optional2", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("exportwatchingwallet", "acct", true) }, staticCmd: func() interface{} { return dcrjson.NewExportWatchingWalletCmd(dcrjson.String("acct"), dcrjson.Bool(true)) }, marshalled: `{"jsonrpc":"1.0","method":"exportwatchingwallet","params":["acct",true],"id":1}`, unmarshalled: &dcrjson.ExportWatchingWalletCmd{ Account: dcrjson.String("acct"), Download: dcrjson.Bool(true), }, }, { name: "getunconfirmedbalance", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getunconfirmedbalance") }, staticCmd: func() interface{} { return dcrjson.NewGetUnconfirmedBalanceCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"getunconfirmedbalance","params":[],"id":1}`, unmarshalled: &dcrjson.GetUnconfirmedBalanceCmd{ Account: nil, }, }, { name: "getunconfirmedbalance optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("getunconfirmedbalance", "acct") }, staticCmd: func() interface{} { return dcrjson.NewGetUnconfirmedBalanceCmd(dcrjson.String("acct")) }, marshalled: `{"jsonrpc":"1.0","method":"getunconfirmedbalance","params":["acct"],"id":1}`, unmarshalled: &dcrjson.GetUnconfirmedBalanceCmd{ Account: dcrjson.String("acct"), }, }, { name: "listaddresstransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listaddresstransactions", `["1Address"]`) }, staticCmd: func() interface{} { return dcrjson.NewListAddressTransactionsCmd([]string{"1Address"}, nil) }, marshalled: `{"jsonrpc":"1.0","method":"listaddresstransactions","params":[["1Address"]],"id":1}`, unmarshalled: &dcrjson.ListAddressTransactionsCmd{ Addresses: []string{"1Address"}, Account: nil, }, }, { name: "listaddresstransactions optional1", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listaddresstransactions", `["1Address"]`, "acct") }, staticCmd: func() interface{} { return dcrjson.NewListAddressTransactionsCmd([]string{"1Address"}, dcrjson.String("acct")) }, marshalled: `{"jsonrpc":"1.0","method":"listaddresstransactions","params":[["1Address"],"acct"],"id":1}`, unmarshalled: &dcrjson.ListAddressTransactionsCmd{ Addresses: []string{"1Address"}, Account: dcrjson.String("acct"), }, }, { name: "listalltransactions", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listalltransactions") }, staticCmd: func() interface{} { return dcrjson.NewListAllTransactionsCmd(nil) }, marshalled: `{"jsonrpc":"1.0","method":"listalltransactions","params":[],"id":1}`, unmarshalled: &dcrjson.ListAllTransactionsCmd{ Account: nil, }, }, { name: "listalltransactions optional", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("listalltransactions", "acct") }, staticCmd: func() interface{} { return dcrjson.NewListAllTransactionsCmd(dcrjson.String("acct")) }, marshalled: `{"jsonrpc":"1.0","method":"listalltransactions","params":["acct"],"id":1}`, unmarshalled: &dcrjson.ListAllTransactionsCmd{ Account: dcrjson.String("acct"), }, }, { name: "recoveraddresses", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("recoveraddresses", "acct", 10) }, staticCmd: func() interface{} { return dcrjson.NewRecoverAddressesCmd("acct", 10) }, marshalled: `{"jsonrpc":"1.0","method":"recoveraddresses","params":["acct",10],"id":1}`, unmarshalled: &dcrjson.RecoverAddressesCmd{ Account: "acct", N: 10, }, }, { name: "walletislocked", newCmd: func() (interface{}, error) { return dcrjson.NewCmd("walletislocked") }, staticCmd: func() interface{} { return dcrjson.NewWalletIsLockedCmd() }, marshalled: `{"jsonrpc":"1.0","method":"walletislocked","params":[],"id":1}`, unmarshalled: &dcrjson.WalletIsLockedCmd{}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the command as created by the new static command // creation function. marshalled, err := dcrjson.MarshalCmd(testID, test.staticCmd()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the command is created without error via the generic // new command creation function. cmd, err := test.newCmd() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the command as created by the generic new command // creation function. marshalled, err = dcrjson.MarshalCmd(testID, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }
// TestChainSvrWsNtfns tests all of the chain server websocket-specific // notifications marshal and unmarshal into valid results include handling of // optional fields being omitted in the marshalled command, while optional // fields with defaults have the default assigned on unmarshalled commands. func TestDcrwalletChainSvrWsNtfns(t *testing.T) { t.Parallel() tests := []struct { name string newNtfn func() (interface{}, error) staticNtfn func() interface{} marshalled string unmarshalled interface{} }{ { name: "ticketpurchase", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("ticketpurchased", "123", 5) }, staticNtfn: func() interface{} { return dcrjson.NewTicketPurchasedNtfn("123", 5) }, marshalled: `{"jsonrpc":"1.0","method":"ticketpurchased","params":["123",5],"id":null}`, unmarshalled: &dcrjson.TicketPurchasedNtfn{ TxHash: "123", Amount: 5, }, }, { name: "votecreated", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("votecreated", "123", "1234", 100, "12345", 1) }, staticNtfn: func() interface{} { return dcrjson.NewVoteCreatedNtfn("123", "1234", 100, "12345", 1) }, marshalled: `{"jsonrpc":"1.0","method":"votecreated","params":["123","1234",100,"12345",1],"id":null}`, unmarshalled: &dcrjson.VoteCreatedNtfn{ TxHash: "123", BlockHash: "1234", Height: 100, SStxIn: "12345", VoteBits: 1, }, }, { name: "revocationcreated", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("revocationcreated", "123", "1234") }, staticNtfn: func() interface{} { return dcrjson.NewRevocationCreatedNtfn("123", "1234") }, marshalled: `{"jsonrpc":"1.0","method":"revocationcreated","params":["123","1234"],"id":null}`, unmarshalled: &dcrjson.RevocationCreatedNtfn{ TxHash: "123", SStxIn: "1234", }, }, { name: "winningtickets", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("winningtickets", "123", 100, map[string]string{"a": "b"}) }, staticNtfn: func() interface{} { return dcrjson.NewWinningTicketsNtfn("123", 100, map[string]string{"a": "b"}) }, marshalled: `{"jsonrpc":"1.0","method":"winningtickets","params":["123",100,{"a":"b"}],"id":null}`, unmarshalled: &dcrjson.WinningTicketsNtfn{ BlockHash: "123", BlockHeight: 100, Tickets: map[string]string{"a": "b"}, }, }, { name: "spentandmissedtickets", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("spentandmissedtickets", "123", 100, 3, map[string]string{"a": "b"}) }, staticNtfn: func() interface{} { return dcrjson.NewSpentAndMissedTicketsNtfn("123", 100, 3, map[string]string{"a": "b"}) }, marshalled: `{"jsonrpc":"1.0","method":"spentandmissedtickets","params":["123",100,3,{"a":"b"}],"id":null}`, unmarshalled: &dcrjson.SpentAndMissedTicketsNtfn{ Hash: "123", Height: 100, StakeDiff: 3, Tickets: map[string]string{"a": "b"}, }, }, { name: "newtickets", newNtfn: func() (interface{}, error) { return dcrjson.NewCmd("newtickets", "123", 100, 3, []string{"a", "b"}) }, staticNtfn: func() interface{} { return dcrjson.NewNewTicketsNtfn("123", 100, 3, []string{"a", "b"}) }, marshalled: `{"jsonrpc":"1.0","method":"newtickets","params":["123",100,3,["a","b"]],"id":null}`, unmarshalled: &dcrjson.NewTicketsNtfn{ Hash: "123", Height: 100, StakeDiff: 3, Tickets: []string{"a", "b"}, }, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Marshal the notification as created by the new static // creation function. The ID is nil for notifications. marshalled, err := dcrjson.MarshalCmd(nil, test.staticNtfn()) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } // Ensure the notification is created without error via the // generic new notification creation function. cmd, err := test.newNtfn() if err != nil { t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ", i, test.name, err) } // Marshal the notification as created by the generic new // notification creation function. The ID is nil for // notifications. marshalled, err = dcrjson.MarshalCmd(nil, cmd) if err != nil { t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !bytes.Equal(marshalled, []byte(test.marshalled)) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) continue } var request dcrjson.Request if err := json.Unmarshal(marshalled, &request); err != nil { t.Errorf("Test #%d (%s) unexpected error while "+ "unmarshalling JSON-RPC request: %v", i, test.name, err) continue } cmd, err = dcrjson.UnmarshalCmd(&request) if err != nil { t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i, test.name, err) continue } if !reflect.DeepEqual(cmd, test.unmarshalled) { t.Errorf("Test #%d (%s) unexpected unmarshalled command "+ "- got %s, want %s", i, test.name, fmt.Sprintf("(%T) %+[1]v", cmd), fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled)) continue } } }