Skip to content

Commit

Permalink
[FABG-932] Add java chaincode integration test (hyperledger#38)
Browse files Browse the repository at this point in the history
[FABG-932] Add java chaincode integration test

Signed-off-by: yakumioto <[email protected]>
  • Loading branch information
yakumioto authored and alikic committed Dec 31, 2019
1 parent 4f8dd0d commit e7b9b0d
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 21 deletions.
1 change: 0 additions & 1 deletion pkg/fab/ccpackager/javapackager/packager.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ func findSource(filePath string) ([]*Descriptor, error) {
if len(relPath) > len(folder) {
relPath = relPath[len(folder)+1:]
}
fmt.Println(relPath, relPath)
descriptors = append(descriptors, &Descriptor{name: relPath, fqp: path})
}
return nil
Expand Down
4 changes: 0 additions & 4 deletions pkg/fab/ccpackager/javapackager/testdata/events_cc/.gitignore

This file was deleted.

This file was deleted.

This file was deleted.

34 changes: 34 additions & 0 deletions test/fixtures/javatestdata/example_cc/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright IBM Corp. 2018 All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
plugins {
id 'com.github.johnrengelman.shadow' version '2.0.3'
id 'java'
}

group 'org.hyperledger.fabric-chaincode-java'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
mavenLocal()
mavenCentral()
}

dependencies {
compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.+'
testCompile group: 'junit', name: 'junit', version: '4.12'
}

shadowJar {
baseName = 'chaincode'
version = null
classifier = null

manifest {
attributes 'Main-Class': 'org.hyperledger.fabric.example.SimpleChaincode'
}
}
7 changes: 7 additions & 0 deletions test/fixtures/javatestdata/example_cc/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright IBM Corp. 2017 All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
rootProject.name = 'fabric-chaincode-example-gradle'

Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
Copyright IBM Corp., DTCC All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.example;

import java.util.List;

import com.google.protobuf.ByteString;
import io.netty.handler.ssl.OpenSsl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;

import static java.nio.charset.StandardCharsets.UTF_8;

public class SimpleChaincode extends ChaincodeBase {

private static Log _logger = LogFactory.getLog(SimpleChaincode.class);

@Override
public Response init(ChaincodeStub stub) {
try {
_logger.info("Init java simple chaincode");
String func = stub.getFunction();
if (!func.equals("init")) {
return newErrorResponse("function other than init is not supported");
}
List<String> args = stub.getParameters();
if (args.size() != 4) {
newErrorResponse("Incorrect number of arguments. Expecting 4");
}
// Initialize the chaincode
String account1Key = args.get(0);
int account1Value = Integer.parseInt(args.get(1));
String account2Key = args.get(2);
int account2Value = Integer.parseInt(args.get(3));

_logger.info(String.format("account %s, value = %s; account %s, value %s", account1Key, account1Value, account2Key, account2Value));
stub.putStringState(account1Key, args.get(1));
stub.putStringState(account2Key, args.get(3));

return newSuccessResponse();
} catch (Throwable e) {
return newErrorResponse(e);
}
}

@Override
public Response invoke(ChaincodeStub stub) {
try {
_logger.info("Invoke java simple chaincode");
String func = stub.getFunction();
List<String> params = stub.getParameters();
if (func.equals("invoke")) {
return invoke(stub, params);
}
if (func.equals("delete")) {
return delete(stub, params);
}
if (func.equals("query")) {
return query(stub, params);
}
return newErrorResponse("Invalid invoke function name. Expecting one of: [\"invoke\", \"delete\", \"query\"]");
} catch (Throwable e) {
return newErrorResponse(e);
}
}

private Response invoke(ChaincodeStub stub, List<String> args) {
if (args.size() != 3) {
return newErrorResponse("Incorrect number of arguments. Expecting 3");
}
String accountFromKey = args.get(0);
String accountToKey = args.get(1);

String accountFromValueStr = stub.getStringState(accountFromKey);
if (accountFromValueStr == null) {
return newErrorResponse(String.format("Entity %s not found", accountFromKey));
}
int accountFromValue = Integer.parseInt(accountFromValueStr);

String accountToValueStr = stub.getStringState(accountToKey);
if (accountToValueStr == null) {
return newErrorResponse(String.format("Entity %s not found", accountToKey));
}
int accountToValue = Integer.parseInt(accountToValueStr);

int amount = Integer.parseInt(args.get(2));

if (amount > accountFromValue) {
return newErrorResponse(String.format("not enough money in account %s", accountFromKey));
}

accountFromValue -= amount;
accountToValue += amount;

_logger.info(String.format("new value of A: %s", accountFromValue));
_logger.info(String.format("new value of B: %s", accountToValue));

stub.putStringState(accountFromKey, Integer.toString(accountFromValue));
stub.putStringState(accountToKey, Integer.toString(accountToValue));

_logger.info("Transfer complete");

return newSuccessResponse("invoke finished successfully", ByteString.copyFrom(accountFromKey + ": " + accountFromValue + " " + accountToKey + ": " + accountToValue, UTF_8).toByteArray());
}

// Deletes an entity from state
private Response delete(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting 1");
}
String key = args.get(0);
// Delete the key from the state in ledger
stub.delState(key);
return newSuccessResponse();
}

// query callback representing the query of a chaincode
private Response query(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting name of the person to query");
}
String key = args.get(0);
//byte[] stateBytes
String val = stub.getStringState(key);
if (val == null) {
return newErrorResponse(String.format("Error: state for %s is null", key));
}
_logger.info(String.format("Query Response:\nName: %s, Amount: %s\n", key, val));
return newSuccessResponse(val, ByteString.copyFrom(val, UTF_8).toByteArray());
}

public static void main(String[] args) {
System.out.println("OpenSSL avaliable: " + OpenSsl.isAvailable());
new SimpleChaincode().start(args);
}

}
50 changes: 50 additions & 0 deletions test/integration/base_test_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ func GetDeployPath() string {
return filepath.Join(metadata.GetProjectPath(), ccPath)
}

// GetJavaDeployPath returns the path to the java chaincode fixtrues
func GetJavaDeployPath() string {
const ccPath = "test/fixtures/javatestdata"
return filepath.Join(metadata.GetProjectPath(), ccPath)
}

// GetChannelConfigTxPath returns the path to the named channel config file
func GetChannelConfigTxPath(filename string) string {
return filepath.Join(metadata.GetProjectPath(), metadata.ChannelConfigPath, filename)
Expand Down Expand Up @@ -314,6 +320,28 @@ func InstantiateChaincode(resMgmt *resmgmt.Client, channelID, ccName, ccPath, cc
)
}

// InstantiateJavaChaincode instantiates the given java chaincode to the given channel
func InstantiateJavaChaincode(resMgmt *resmgmt.Client, channelID, ccName, ccPath, ccVersion string, ccPolicyStr string, args [][]byte, collConfigs ...*pb.CollectionConfig) (resmgmt.InstantiateCCResponse, error) {
ccPolicy, err := cauthdsl.FromString(ccPolicyStr)
if err != nil {
return resmgmt.InstantiateCCResponse{}, errors.Wrapf(err, "error creating CC policy [%s]", ccPolicyStr)
}

return resMgmt.InstantiateCC(
channelID,
resmgmt.InstantiateCCRequest{
Name: ccName,
Path: ccPath,
Version: ccVersion,
Lang: pb.ChaincodeSpec_JAVA,
Args: args,
Policy: ccPolicy,
CollConfig: collConfigs,
},
resmgmt.WithRetry(retry.DefaultResMgmtOpts),
)
}

// UpgradeChaincode upgrades the given chaincode on the given channel
func UpgradeChaincode(resMgmt *resmgmt.Client, channelID, ccName, ccPath, ccVersion string, ccPolicyStr string, args [][]byte, collConfigs ...*pb.CollectionConfig) (resmgmt.UpgradeCCResponse, error) {
ccPolicy, err := cauthdsl.FromString(ccPolicyStr)
Expand All @@ -335,6 +363,28 @@ func UpgradeChaincode(resMgmt *resmgmt.Client, channelID, ccName, ccPath, ccVers
)
}

// UpgradeJavaChaincode upgrades the given java chaincode on the given channel
func UpgradeJavaChaincode(resMgmt *resmgmt.Client, channelID, ccName, ccPath, ccVersion string, ccPolicyStr string, args [][]byte, collConfigs ...*pb.CollectionConfig) (resmgmt.UpgradeCCResponse, error) {
ccPolicy, err := cauthdsl.FromString(ccPolicyStr)
if err != nil {
return resmgmt.UpgradeCCResponse{}, errors.Wrapf(err, "error creating CC policy [%s]", ccPolicyStr)
}

return resMgmt.UpgradeCC(
channelID,
resmgmt.UpgradeCCRequest{
Name: ccName,
Path: ccPath,
Version: ccVersion,
Lang: pb.ChaincodeSpec_JAVA,
Args: args,
Policy: ccPolicy,
CollConfig: collConfigs,
},
resmgmt.WithRetry(retry.DefaultResMgmtOpts),
)
}

// DiscoverLocalPeers queries the local peers for the given MSP context and returns all of the peers. If
// the number of peers does not match the expected number then an error is returned.
func DiscoverLocalPeers(ctxProvider contextAPI.ClientProvider, expectedPeers int) ([]fabAPI.Peer, error) {
Expand Down
80 changes: 80 additions & 0 deletions test/integration/pkg/client/channel/channel_client_javacc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
Copyright Mioto Yaku All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package channel

import (
"testing"
"time"

"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
"github.com/hyperledger/fabric-sdk-go/test/integration"
"github.com/stretchr/testify/require"
)

// TestJavaChaincodeInstallInstantiateAndUpgrade tests install java chaincode,
// instantiate java chaincode upgrade java chaincode
func TestJavaChaincodeInstallInstantiateAndUpgrade(t *testing.T) {
sdk := mainSDK

orgsContext := setupMultiOrgContext(t, sdk)
err := integration.EnsureChannelCreatedAndPeersJoined(t, sdk, orgChannelID, "orgchannel.tx", orgsContext)
require.NoError(t, err)

ccID := integration.GenerateExampleJavaID(false)

err = integration.InstallExampleJavaChaincode(orgsContext, ccID)
require.NoError(t, err)

err = integration.InstantiateExampleJavaChaincode(orgsContext, orgChannelID, ccID, "OR('Org1MSP.member','Org2MSP.member')")
require.NoError(t, err)

err = integration.UpgradeExampleJavaChaincode(orgsContext, orgChannelID, ccID, "OR('Org1MSP.member','Org2MSP.member')")
require.NoError(t, err)

//prepare context
org1ChannelClientContext := sdk.ChannelContext(orgChannelID, fabsdk.WithUser(org1User), fabsdk.WithOrg(org1Name))

//get channel client
chClient, err := channel.New(org1ChannelClientContext)
if err != nil {
t.Fatalf("Failed to create new channel client: %s", err)
}

// test query
testJavaQuery(t, chClient, "200", ccID, "b")
}

func testJavaQuery(t *testing.T, chClient *channel.Client, expected string, ccID, key string) {
const (
maxRetries = 10
retrySleep = 500 * time.Millisecond
)

for r := 0; r < 10; r++ {
response, err := chClient.Query(channel.Request{ChaincodeID: ccID, Fcn: "query", Args: [][]byte{[]byte(key)}},
channel.WithRetry(retry.DefaultChannelOpts))
if err == nil {
actual := string(response.Payload)
if actual == expected {
return
}

t.Logf("On Attempt [%d / %d]: Response didn't match expected value [%s, %s]", r, maxRetries, actual, expected)
} else {
t.Logf("On Attempt [%d / %d]: failed to invoke example cc '%s' with Args:[%+v], error: %+v", r, maxRetries, ccID, integration.ExampleCCQueryArgs(key), err)
if r < 9 {
t.Logf("will retry in %v", retrySleep)
}
}

time.Sleep(retrySleep)
}

t.Fatal("Exceeded max retries")
}
7 changes: 7 additions & 0 deletions test/integration/pkg/client/resmgmt/resmgmt_queries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
"github.com/hyperledger/fabric-sdk-go/test/integration"
)

func TestResMgmtClientQueries(t *testing.T) {
Expand Down Expand Up @@ -41,6 +42,12 @@ func TestResMgmtClientQueries(t *testing.T) {

testQueryChannels(t, testSetup.ChannelID, target, client)

// test java chaincode installed and instantiated
javaCCID := integration.GenerateExampleJavaID(false)

testInstalledChaincodes(t, javaCCID, target, client)

testInstantiatedChaincodes(t, orgChannelID, javaCCID, target, client)
}

func testInstantiatedChaincodes(t *testing.T, channelID string, ccID string, target string, client *resmgmt.Client) {
Expand Down
Loading

0 comments on commit e7b9b0d

Please sign in to comment.