| 
									
										
										
										
											2016-04-14 18:18:24 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | package rpc | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bufio" | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type RWC struct { | 
					
						
							|  |  |  | 	*bufio.ReadWriter | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (rwc *RWC) Close() error { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestJSONRequestParsing(t *testing.T) { | 
					
						
							|  |  |  | 	server := NewServer() | 
					
						
							|  |  |  | 	service := new(Service) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := server.RegisterName("calc", service); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("%v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req := bytes.NewBufferString(`{"id": 1234, "jsonrpc": "2.0", "method": "calc_add", "params": [11, 22]}`) | 
					
						
							|  |  |  | 	var str string | 
					
						
							|  |  |  | 	reply := bytes.NewBufferString(str) | 
					
						
							|  |  |  | 	rw := &RWC{bufio.NewReadWriter(bufio.NewReader(req), bufio.NewWriter(reply))} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	codec := NewJSONCodec(rw) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	requests, batch, err := codec.ReadRequestHeaders() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("%v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if batch { | 
					
						
							|  |  |  | 		t.Fatalf("Request isn't a batch") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(requests) != 1 { | 
					
						
							|  |  |  | 		t.Fatalf("Expected 1 request but got %d requests - %v", len(requests), requests) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if requests[0].service != "calc" { | 
					
						
							|  |  |  | 		t.Fatalf("Expected service 'calc' but got '%s'", requests[0].service) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if requests[0].method != "add" { | 
					
						
							|  |  |  | 		t.Fatalf("Expected method 'Add' but got '%s'", requests[0].method) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 	if rawId, ok := requests[0].id.(*json.RawMessage); ok { | 
					
						
							|  |  |  | 		id, e := strconv.ParseInt(string(*rawId), 0, 64) | 
					
						
							|  |  |  | 		if e != nil { | 
					
						
							|  |  |  | 			t.Fatalf("%v", e) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if id != 1234 { | 
					
						
							| 
									
										
										
										
											2016-04-15 11:06:57 +02:00
										 |  |  | 			t.Fatalf("Expected id 1234 but got %d", id) | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		t.Fatalf("invalid request, expected *json.RawMesage got %T", requests[0].id) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var arg int | 
					
						
							|  |  |  | 	args := []reflect.Type{reflect.TypeOf(arg), reflect.TypeOf(arg)} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v, err := codec.ParseRequestArguments(args, requests[0].params) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("%v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(v) != 2 { | 
					
						
							|  |  |  | 		t.Fatalf("Expected 2 argument values, got %d", len(v)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if v[0].Int() != 11 || v[1].Int() != 22 { | 
					
						
							|  |  |  | 		t.Fatalf("expected %d == 11 && %d == 22", v[0].Int(), v[1].Int()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestJSONRequestParamsParsing(t *testing.T) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		stringT = reflect.TypeOf("") | 
					
						
							|  |  |  | 		intT    = reflect.TypeOf(0) | 
					
						
							|  |  |  | 		intPtrT = reflect.TypeOf(new(int)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		stringV = reflect.ValueOf("abc") | 
					
						
							|  |  |  | 		i       = 1 | 
					
						
							|  |  |  | 		intV    = reflect.ValueOf(i) | 
					
						
							|  |  |  | 		intPtrV = reflect.ValueOf(&i) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var validTests = []struct { | 
					
						
							|  |  |  | 		input    string | 
					
						
							|  |  |  | 		argTypes []reflect.Type | 
					
						
							|  |  |  | 		expected []reflect.Value | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{`[]`, []reflect.Type{}, []reflect.Value{}}, | 
					
						
							|  |  |  | 		{`[]`, []reflect.Type{intPtrT}, []reflect.Value{intPtrV}}, | 
					
						
							|  |  |  | 		{`[1]`, []reflect.Type{intT}, []reflect.Value{intV}}, | 
					
						
							|  |  |  | 		{`[1,"abc"]`, []reflect.Type{intT, stringT}, []reflect.Value{intV, stringV}}, | 
					
						
							|  |  |  | 		{`[null]`, []reflect.Type{intPtrT}, []reflect.Value{intPtrV}}, | 
					
						
							|  |  |  | 		{`[null,"abc"]`, []reflect.Type{intPtrT, stringT, intPtrT}, []reflect.Value{intPtrV, stringV, intPtrV}}, | 
					
						
							|  |  |  | 		{`[null,"abc",null]`, []reflect.Type{intPtrT, stringT, intPtrT}, []reflect.Value{intPtrV, stringV, intPtrV}}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	codec := jsonCodec{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range validTests { | 
					
						
							|  |  |  | 		params := (json.RawMessage)([]byte(test.input)) | 
					
						
							|  |  |  | 		args, err := codec.ParseRequestArguments(test.argTypes, params) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var match []interface{} | 
					
						
							|  |  |  | 		json.Unmarshal([]byte(test.input), &match) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(args) != len(test.argTypes) { | 
					
						
							|  |  |  | 			t.Fatalf("expected %d parsed args, got %d", len(test.argTypes), len(args)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for i, arg := range args { | 
					
						
							|  |  |  | 			expected := test.expected[i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if arg.Kind() != expected.Kind() { | 
					
						
							|  |  |  | 				t.Errorf("expected type for param %d in %s", i, test.input) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if arg.Kind() == reflect.Int && arg.Int() != expected.Int() { | 
					
						
							|  |  |  | 				t.Errorf("expected int(%d), got int(%d) in %s", expected.Int(), arg.Int(), test.input) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if arg.Kind() == reflect.String && arg.String() != expected.String() { | 
					
						
							|  |  |  | 				t.Errorf("expected string(%s), got string(%s) in %s", expected.String(), arg.String(), test.input) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var invalidTests = []struct { | 
					
						
							|  |  |  | 		input    string | 
					
						
							|  |  |  | 		argTypes []reflect.Type | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{`[]`, []reflect.Type{intT}}, | 
					
						
							|  |  |  | 		{`[null]`, []reflect.Type{intT}}, | 
					
						
							|  |  |  | 		{`[1]`, []reflect.Type{stringT}}, | 
					
						
							|  |  |  | 		{`[1,2]`, []reflect.Type{stringT}}, | 
					
						
							|  |  |  | 		{`["abc", null]`, []reflect.Type{stringT, intT}}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range invalidTests { | 
					
						
							|  |  |  | 		if _, err := codec.ParseRequestArguments(test.argTypes, test.input); err == nil { | 
					
						
							|  |  |  | 			t.Errorf("expected test %d - %s to fail", i, test.input) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |