Beispiel #1
0
func TestServerOpenchain_API_GetBlockByNumber(t *testing.T) {
	// Construct a ledger with 0 blocks.
	ledger.InitTestLedger(t)

	// Initialize the OpenchainServer object.
	server, err := NewOpenchainServerWithPeerInfo(new(peerInfo))
	if err != nil {
		t.Logf("Error creating OpenchainServer: %s", err)
		t.Fail()
	}

	// Attempt to retrieve the 0th block from the blockchain. There are no blocks
	// in this blockchain, therefore this test should intentionally fail.

	block, err := server.GetBlockByNumber(context.Background(), &protos.BlockNumber{Number: 0})
	if err != nil {
		// Success
		t.Logf("Error retrieving Block from blockchain: %s", err)
	} else {
		// Failure
		t.Logf("Attempting to retrieve from empty blockchain: %v", block)
		t.Fail()
	}

	// Construct a ledger with 3 blocks.
	ledger1 := ledger.InitTestLedger(t)
	buildTestLedger1(ledger1, t)
	server.ledger = ledger1

	// Retrieve the 0th block from the blockchain.
	block, err = server.GetBlockByNumber(context.Background(), &protos.BlockNumber{Number: 0})
	if err != nil {
		t.Logf("Error retrieving Block from blockchain: %s", err)
		t.Fail()
	} else {
		t.Logf("Block #0: %v", block)
	}

	// Retrieve the 3rd block from the blockchain, blocks are numbered starting
	// from 0.
	block, err = server.GetBlockByNumber(context.Background(), &protos.BlockNumber{Number: 2})
	if err != nil {
		t.Logf("Error retrieving Block from blockchain: %s", err)
		t.Fail()
	} else {
		t.Logf("Block #2: %v", block)
	}

	// Retrieve the 5th block from the blockchain. There are only 3 blocks in this
	// blockchain, therefore this test should intentionally fail.
	block, err = server.GetBlockByNumber(context.Background(), &protos.BlockNumber{Number: 4})
	if err != nil {
		// Success.
		t.Logf("Error retrieving Block from blockchain: %s", err)
	} else {
		// Failure
		t.Logf("Trying to retrieve non-existent block from blockchain: %v", block)
		t.Fail()
	}
}
Beispiel #2
0
func TestServerOpenchainREST_API_Chaincode_Query(t *testing.T) {
	// Construct a ledger with 3 blocks.
	ledger := ledger.InitTestLedger(t)
	buildTestLedger1(ledger, t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	// Test query without params
	httpResponse, body := performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query"}`))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res := parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidParams.Code {
		t.Errorf("Expected an error when sending missing params, but got %#v", res.Error)
	}

	// Test query with non-existing chaincode name
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"non-existing"},"ctorMsg":{"function":"Init","args":[]}}}`))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != ChaincodeQueryError.Code {
		t.Errorf("Expected an error when sending non-existing chaincode path, but got %#v", res.Error)
	}

	// Test query with fail function
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"function":"fail","args":[]}}}`))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != ChaincodeQueryError.Code {
		t.Errorf("Expected an error when chaincode query fails, but got %#v", res.Error)
	}
	if res.Error.Data != "Error when querying chaincode: Query failure with special-\" chars" {
		t.Errorf("Expected an error message when chaincode query fails, but got %#v", res.Error.Data)
	}

	// Test query with get_owner function
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"query","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"function":"get_owner","args":[]}}}`))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error != nil {
		t.Errorf("Expected success but got %#v", res.Error)
	}
	if res.Result.Status != "OK" {
		t.Errorf("Expected OK but got %#v", res.Result.Status)
	}
	if res.Result.Message != "get_owner_query_result" {
		t.Errorf("Expected 'get_owner_query_result' but got '%v'", res.Result.Message)
	}
}
Beispiel #3
0
func TestServerOpenchain_API_GetBlockCount(t *testing.T) {
	// Must initialize the ledger singleton before initializing the
	// OpenchainServer, as it needs that pointer.

	// Construct a ledger with 0 blocks.
	ledger := ledger.InitTestLedger(t)

	// Initialize the OpenchainServer object.
	server, err := NewOpenchainServerWithPeerInfo(new(peerInfo))
	if err != nil {
		t.Logf("Error creating OpenchainServer: %s", err)
		t.Fail()
	}

	// Retrieve the current number of blocks in the blockchain. There are no blocks
	// in this blockchain, therefore this test should intentionally fail.
	count, err := server.GetBlockCount(context.Background(), &empty.Empty{})
	if err != nil {
		// Success
		t.Logf("Error retrieving BlockCount from blockchain: %s", err)
	} else {
		// Failure
		t.Logf("Attempting to query an empty blockchain: %v", count.Count)
		t.Fail()
	}

	// Add three 3 blocks to ledger.
	buildTestLedger1(ledger, t)
	// Retrieve the current number of blocks in the blockchain. Must be 3.
	count, err = server.GetBlockCount(context.Background(), &empty.Empty{})
	if err != nil {
		t.Logf("Error retrieving BlockCount from blockchain: %s", err)
		t.Fail()
	} else if count.Count != 3 {
		t.Logf("Error! Blockchain must have 3 blocks!")
		t.Fail()
	} else {
		t.Logf("Current BlockCount: %v", count.Count)
	}

	// Add 5 more blocks to ledger.
	buildTestLedger2(ledger, t)
	// Retrieve the current number of blocks in the blockchain. Must be 5.
	count, err = server.GetBlockCount(context.Background(), &empty.Empty{})
	if err != nil {
		t.Logf("Error retrieving BlockCount from blockchain: %s", err)
		t.Fail()
	} else if count.Count != 8 {
		t.Logf("Error! Blockchain must have 8 blocks!")
		t.Fail()
	} else {
		t.Logf("Current BlockCount: %v", count.Count)
	}
}
Beispiel #4
0
func TestServerOpenchainREST_API_GetBlockByNumber(t *testing.T) {
	// Construct a ledger with 0 blocks.
	ledger := ledger.InitTestLedger(t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	body := performHTTPGet(t, httpServer.URL+"/chain/blocks/0")
	res := parseRESTResult(t, body)
	if res.Error == "" {
		t.Errorf("Expected an error when retrieving block 0 of an empty blockchain, but got none")
	}

	// add 3 blocks to the ledger
	buildTestLedger1(ledger, t)

	// Retrieve the first block from the blockchain (block number = 0)
	body0 := performHTTPGet(t, httpServer.URL+"/chain/blocks/0")
	var block0 protos.Block
	err := json.Unmarshal(body0, &block0)
	if err != nil {
		t.Fatalf("Invalid JSON response: %v", err)
	}

	// Retrieve the 3rd block from the blockchain (block number = 2)
	body2 := performHTTPGet(t, httpServer.URL+"/chain/blocks/2")
	var block2 protos.Block
	err = json.Unmarshal(body2, &block2)
	if err != nil {
		t.Fatalf("Invalid JSON response: %v", err)
	}
	if len(block2.Transactions) != 2 {
		t.Errorf("Expected block to contain 2 transactions but got %v", len(block2.Transactions))
	}

	// Retrieve the 5th block from the blockchain (block number = 4), which
	// should fail because the ledger has only 3 blocks.
	body4 := performHTTPGet(t, httpServer.URL+"/chain/blocks/4")
	res4 := parseRESTResult(t, body4)
	if res4.Error == "" {
		t.Errorf("Expected an error when retrieving non-existing block, but got none")
	}

	// Illegal block number
	body = performHTTPGet(t, httpServer.URL+"/chain/blocks/NOT_A_NUMBER")
	res = parseRESTResult(t, body)
	if res.Error == "" {
		t.Errorf("Expected an error when URL doesn't have a number, but got none")
	}
}
Beispiel #5
0
func TestServerOpenchainREST_API_Chaincode_Invoke(t *testing.T) {
	// Construct a ledger with 3 blocks.
	ledger := ledger.InitTestLedger(t)
	buildTestLedger1(ledger, t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	// Test invoke without params
	httpResponse, body := performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke"}`))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res := parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidParams.Code {
		t.Errorf("Expected an error when sending missing params, but got %#v", res.Error)
	}

	// Login
	performHTTPPost(t, httpServer.URL+"/registrar", []byte(`{"enrollId":"myuser","enrollSecret":"password"}`))

	// Test invoke with "fail" function
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"Function":"`+fail_func+`","args":[]},"secureContext":"myuser"}}`))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != ChaincodeInvokeError.Code {
		t.Errorf("Expected an error when sending non-existing chaincode path, but got %#v", res.Error)
	}

	// Test invoke with "change_owner" function
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"invoke","params":{"type":1,"chaincodeID":{"name":"dummy"},"ctorMsg":{"Function":"`+change_owner_func+`","args":[]},"secureContext":"myuser"}}`))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error != nil {
		t.Errorf("Expected success but got %#v", res.Error)
	}
	if res.Result.Status != "OK" {
		t.Errorf("Expected OK but got %#v", res.Result.Status)
	}
	if res.Result.Message != "change_owner_invoke_result" {
		t.Errorf("Expected 'change_owner_invoke_result' but got '%v'", res.Result.Message)
	}
}
Beispiel #6
0
func TestGenesis(t *testing.T) {

	//use a different address than what we usually use for "peer"
	//we override the peerAddress set in chaincode_support.go
	peerAddress := "0.0.0.0:50303"

	lis, err := net.Listen("tcp", peerAddress)
	if err != nil {
		t.Fail()
		t.Logf("Error starting peer listener %s", err)
		return
	}

	var opts []grpc.ServerOption
	if viper.GetBool("peer.tls.enabled") {
		creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"), viper.GetString("peer.tls.key.file"))
		if err != nil {
			grpclog.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	grpcServer := grpc.NewServer(opts...)

	getPeerEndpoint := func() (*protos.PeerEndpoint, error) {
		return &protos.PeerEndpoint{ID: &protos.PeerID{Name: "testpeer"}, Address: peerAddress}, nil
	}

	ccStartupTimeout := time.Duration(30000) * time.Millisecond
	protos.RegisterChaincodeSupportServer(grpcServer, chaincode.NewChaincodeSupport(chaincode.DefaultChain, getPeerEndpoint, false, ccStartupTimeout, nil))

	go grpcServer.Serve(lis)

	ledger := ledger.InitTestLedger(t)

	if ledger.GetBlockchainSize() != 0 {
		t.Fatalf("Expected blockchain size of 0, but got %d", ledger.GetBlockchainSize())
	}

	makeGenesisErr := MakeGenesis()
	if makeGenesisErr != nil {
		t.Fatalf("Error creating genesis block, %s", makeGenesisErr)
	}
	if ledger.GetBlockchainSize() != 1 {
		t.Fatalf("Expected blockchain size of 1, but got %d", ledger.GetBlockchainSize())
	}
}
Beispiel #7
0
func TestServerOpenchainREST_API_GetTransactionByUUID(t *testing.T) {
	startTime := time.Now().Unix()

	// Construct a ledger with 3 blocks.
	ledger := ledger.InitTestLedger(t)
	buildTestLedger1(ledger, t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	body := performHTTPGet(t, httpServer.URL+"/transactions/NON-EXISTING-UUID")
	res := parseRESTResult(t, body)
	if res.Error == "" {
		t.Errorf("Expected an error when retrieving non-existing transaction, but got none")
	}

	block1, err := ledger.GetBlockByNumber(1)
	if err != nil {
		t.Fatalf("Can't fetch first block from ledger: %v", err)
	}
	firstTx := block1.Transactions[0]

	body1 := performHTTPGet(t, httpServer.URL+"/transactions/"+firstTx.Txid)
	var tx1 protos.Transaction
	err = json.Unmarshal(body1, &tx1)
	if err != nil {
		t.Fatalf("Invalid JSON response: %v", err)
	}
	if tx1.Txid != firstTx.Txid {
		t.Errorf("Expected transaction uuid to be '%v' but got '%v'", firstTx.Txid, tx1.Txid)
	}
	if tx1.Timestamp.Seconds < startTime {
		t.Errorf("Expected transaction timestamp (%v) to be after the start time (%v)", tx1.Timestamp.Seconds, startTime)
	}

	badBody := performHTTPGet(t, httpServer.URL+"/transactions/with-\"-chars-in-the-URL")
	badRes := parseRESTResult(t, badBody)
	if badRes.Error == "" {
		t.Errorf("Expected a proper error when retrieving transaction with bad UUID")
	}
}
Beispiel #8
0
func TestServerOpenchain_API_GetBlockchainInfo(t *testing.T) {
	// Construct a ledger with 0 blocks.
	ledger := ledger.InitTestLedger(t)
	// Initialize the OpenchainServer object.
	server, err := NewOpenchainServerWithPeerInfo(new(peerInfo))
	if err != nil {
		t.Logf("Error creating OpenchainServer: %s", err)
		t.Fail()
	}
	// Attempt to retrieve the blockchain info. There are no blocks
	// in this blockchain, therefore this test should intentionally fail.
	info, err := server.GetBlockchainInfo(context.Background(), &empty.Empty{})
	if err != nil {
		// Success
		t.Logf("Error retrieving blockchain info: %s", err)
	} else {
		// Failure
		t.Logf("Error attempting to retrive info from emptry blockchain: %v", info)
		t.Fail()
	}

	// add 3 blocks to ledger.
	buildTestLedger1(ledger, t)
	// Attempt to retrieve the blockchain info.
	info, err = server.GetBlockchainInfo(context.Background(), &empty.Empty{})
	if err != nil {
		t.Logf("Error retrieving blockchain info: %s", err)
		t.Fail()
	} else {
		t.Logf("Blockchain 1 info: %v", info)
	}

	// add 5 blocks more.
	buildTestLedger2(ledger, t)
	// Attempt to retrieve the blockchain info.
	info, err = server.GetBlockchainInfo(context.Background(), &empty.Empty{})
	if err != nil {
		t.Logf("Error retrieving blockchain info: %s", err)
		t.Fail()
	} else {
		t.Logf("Blockchain 2 info: %v", info)
	}
}
Beispiel #9
0
func TestServerOpenchainREST_API_GetBlockchainInfo(t *testing.T) {
	// Construct a ledger with 0 blocks.
	ledger := ledger.InitTestLedger(t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	body := performHTTPGet(t, httpServer.URL+"/chain")
	res := parseRESTResult(t, body)
	if res.Error == "" {
		t.Errorf("Expected an error when retrieving empty blockchain, but got none")
	}

	// add 3 blocks to the ledger
	buildTestLedger1(ledger, t)

	body3 := performHTTPGet(t, httpServer.URL+"/chain")
	var blockchainInfo3 protos.BlockchainInfo
	err := json.Unmarshal(body3, &blockchainInfo3)
	if err != nil {
		t.Fatalf("Invalid JSON response: %v", err)
	}
	if blockchainInfo3.Height != 3 {
		t.Errorf("Expected blockchain height to be 3 but got %v", blockchainInfo3.Height)
	}

	// add 5 more blocks more to the ledger
	buildTestLedger2(ledger, t)

	body8 := performHTTPGet(t, httpServer.URL+"/chain")
	var blockchainInfo8 protos.BlockchainInfo
	err = json.Unmarshal(body8, &blockchainInfo8)
	if err != nil {
		t.Fatalf("Invalid JSON response: %v", err)
	}
	if blockchainInfo8.Height != 8 {
		t.Errorf("Expected blockchain height to be 8 but got %v", blockchainInfo8.Height)
	}
}
Beispiel #10
0
func TestServerOpenchain_API_GetState(t *testing.T) {
	ledger1 := ledger.InitTestLedger(t)
	// Construct a blockchain with 3 blocks.
	buildTestLedger1(ledger1, t)

	// Initialize the OpenchainServer object.
	server, err := NewOpenchainServerWithPeerInfo(new(peerInfo))
	if err != nil {
		t.Logf("Error creating OpenchainServer: %s", err)
		t.Fail()
	}

	// Retrieve the current number of blocks in the blockchain. Must be 3.
	val, stateErr := server.GetState(context.Background(), "MyContract1", "code")
	if stateErr != nil {
		t.Fatalf("Error retrieving state: %s", stateErr)
	} else if bytes.Compare(val, []byte("code example")) != 0 {
		t.Fatalf("Expected %s, but got %s", []byte("code example"), val)
	}

}
Beispiel #11
0
func TestServerOpenchainREST_API_Chaincode_Deploy(t *testing.T) {
	// Construct a ledger with 3 blocks.
	ledger := ledger.InitTestLedger(t)
	buildTestLedger1(ledger, t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	// Test deploy without params
	httpResponse, body := performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"deploy"}`))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res := parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidParams.Code {
		t.Errorf("Expected an error when sending missing params, but got %#v", res.Error)
	}

	// Login
	performHTTPPost(t, httpServer.URL+"/registrar", []byte(`{"enrollId":"myuser","enrollSecret":"password"}`))

	// Test deploy with invalid chaincode path
	requestBody := `{
		"jsonrpc": "2.0",
		"ID": 123,
		"method": "deploy",
		"params": {
			"type": 1,
			"chaincodeID": {
				"path": "non-existing"
			},
			"ctorMsg": {
				"args": ["` +
		init_func +
		`"]
			},
			"secureContext": "myuser"
		}
	}`
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(requestBody))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != ChaincodeDeployError.Code {
		t.Errorf("Expected an error when sending non-existing chaincode path, but got %#v", res.Error)
	}

	// Test deploy without username
	requestBody = `{
		"jsonrpc": "2.0",
		"ID": 123,
		"method": "deploy",
		"params": {
			"type": 1,
			"chaincodeID": {
				"path": "github.com/hyperledger/fabric/core/rest/test_chaincode"
			},
			"ctorMsg": {
				"args": ["` +
		init_func +
		`"]
			}
		}
	}`
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(requestBody))
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidParams.Code {
		t.Errorf("Expected an error when sending without username, but got %#v", res.Error)
	}

	// Test deploy with real chaincode path
	requestBody = `{
		"jsonrpc": "2.0",
		"ID": 123,
		"method": "deploy",
		"params": {
			"type": 1,
			"chaincodeID": {
				"path": "github.com/hyperledger/fabric/core/rest/test_chaincode"
			},
			"ctorMsg": {
				"args": ["` +
		init_func +
		`"]
			},
			"secureContext": "myuser"
		}
	}`
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(requestBody))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error != nil {
		t.Errorf("Expected success but got %#v", res.Error)
	}
	if res.Result.Status != "OK" {
		t.Errorf("Expected OK but got %#v", res.Result.Status)
	}
	if res.Result.Message != "new_name_for_deployed_chaincode" {
		t.Errorf("Expected 'new_name_for_deployed_chaincode' but got '%#v'", res.Result.Message)
	}
}
Beispiel #12
0
func TestServerOpenchainREST_API_Chaincode_InvalidRequests(t *testing.T) {
	// Construct a ledger with 3 blocks.
	ledger := ledger.InitTestLedger(t)
	buildTestLedger1(ledger, t)

	initGlobalServerOpenchain(t)

	// Start the HTTP REST test server
	httpServer := httptest.NewServer(buildOpenchainRESTRouter())
	defer httpServer.Close()

	// Test empty POST payload
	httpResponse, body := performHTTPPost(t, httpServer.URL+"/chaincode", []byte{})
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res := parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidRequest.Code {
		t.Errorf("Expected an error when sending empty payload, but got %#v", res.Error)
	}

	// Test invalid POST payload
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte("{,,,"))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != ParseError.Code {
		t.Errorf("Expected an error when sending invalid JSON payload, but got %#v", res.Error)
	}

	// Test request without ID (=notification) results in no response
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0"}`))
	if httpResponse.StatusCode != http.StatusOK {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusOK, httpResponse.StatusCode)
	}
	if len(body) != 0 {
		t.Errorf("Expected an empty response body to notification, but got %#v", string(body))
	}

	// Test missing JSON RPC version
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"ID":123}`))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidRequest.Code {
		t.Errorf("Expected an error when sending missing jsonrpc version, but got %#v", res.Error)
	}

	// Test illegal JSON RPC version
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"0.0","ID":123}`))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidRequest.Code {
		t.Errorf("Expected an error when sending illegal jsonrpc version, but got %#v", res.Error)
	}

	// Test missing JSON RPC method
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123}`))
	if httpResponse.StatusCode != http.StatusBadRequest {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusBadRequest, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != InvalidRequest.Code {
		t.Errorf("Expected an error when sending missing jsonrpc method, but got %#v", res.Error)
	}

	// Test illegal JSON RPC method
	httpResponse, body = performHTTPPost(t, httpServer.URL+"/chaincode", []byte(`{"jsonrpc":"2.0","ID":123,"method":"non_existing"}`))
	if httpResponse.StatusCode != http.StatusNotFound {
		t.Errorf("Expected an HTTP status code %#v but got %#v", http.StatusNotFound, httpResponse.StatusCode)
	}
	res = parseRPCResponse(t, body)
	if res.Error == nil || res.Error.Code != MethodNotFound.Code {
		t.Errorf("Expected an error when sending illegal jsonrpc method, but got %#v", res.Error)
	}

}