diff --git a/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/README.md b/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/README.md new file mode 100644 index 00000000..22338f1d --- /dev/null +++ b/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/README.md @@ -0,0 +1,23 @@ +# Debug Chaincode with MockShim +Baohua Yang, 2019-01-17 + +The package will demonstrate how to debug the chaincode with the MockShim lib. + +This way is more efficient and quick to debug locally without any fabric network setup. + +## Usage + +Unzip the package and enter the package path, then run + +```bash +# Regular testing should return OK +$ go test . + +# Debug with more logs output +$ go test -v . +``` + +## Files + +* chaincode_example02.go: example02 chaincode from HLF repo; +* cc_test.go: test code to verify the example02 chaincode logic. diff --git a/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/cc_test.go b/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/cc_test.go new file mode 100644 index 00000000..6fb11c2c --- /dev/null +++ b/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/cc_test.go @@ -0,0 +1,58 @@ +package main + +import ( + "strconv" + "testing" + + "github.com/hyperledger/fabric/core/chaincode/shim" +) + +// TestMockShim test the chaincode with MockShim +func TestMockShim(t *testing.T) { + var Aval int + var err error + + // Instantiate mockStub using the sample example02 chaincode + stub := shim.NewMockStub("mockStub", new(SimpleChaincode)) + if stub == nil { + t.Fatalf("MockStub creation failed") + } + + // Init with tx_uuid, args + result := stub.MockInit("000001", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}) + if result.Status != shim.OK { + t.Fatalf("Error to Init the chaincode: %+v", result) + } + + // Query the existing result + result = stub.MockInvoke("000002", [][]byte{[]byte("query"), []byte("a")}) + if result.Status != shim.OK { + t.Fatalf("Error to Invoke.query the chaincode: %+v", result) + } + Aval, err = strconv.Atoi(string(result.Payload)) + if err != nil { + t.Errorf("Expecting integer value for query result") + } + if Aval != 100 { + t.Errorf("Value is not equal to expected from query result") + } + + // Invoke to transfer + result = stub.MockInvoke("000003", [][]byte{[]byte("invoke"), []byte("a"), []byte("b"), []byte("10")}) + if result.Status != shim.OK { + t.Fatalf("Error to Invoke.invoke the chaincode: %+v", result) + } + + // Query the existing result + result = stub.MockInvoke("000004", [][]byte{[]byte("query"), []byte("a")}) + if result.Status != shim.OK { + t.Fatalf("Error to Invoke.query the chaincode: %+v", result) + } + Aval, err = strconv.Atoi(string(result.Payload)) + if err != nil { + t.Errorf("Expecting integer value for query result") + } + if Aval != 90 { + t.Errorf("Value is not equal to expected from query result") + } +} diff --git a/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/chaincode_example02.go b/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/chaincode_example02.go new file mode 100644 index 00000000..945084b1 --- /dev/null +++ b/hyperledger_fabric/latest/examples/chaincode/go/cc02_mockTest/chaincode_example02.go @@ -0,0 +1,200 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of +//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has +//to be modified as well with the new ID of chaincode_example02. +//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of +//hard-coding. + +import ( + "fmt" + "strconv" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("ex02 Init") + _, args := stub.GetFunctionAndParameters() + var A, B string // Entities + var Aval, Bval int // Asset holdings + var err error + + if len(args) != 4 { + fmt.Printf("args = %+v\n", args) + return shim.Error("Incorrect number of arguments. Expecting 4") + } + + // Initialize the chaincode + A = args[0] + Aval, err = strconv.Atoi(args[1]) + if err != nil { + return shim.Error("Expecting integer value for asset holding") + } + B = args[2] + Bval, err = strconv.Atoi(args[3]) + if err != nil { + return shim.Error("Expecting integer value for asset holding") + } + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(nil) +} + +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("ex02 Invoke") + function, args := stub.GetFunctionAndParameters() + if function == "invoke" { + // Make payment of X units from A to B + return t.invoke(stub, args) + } else if function == "delete" { + // Deletes an entity from its state + return t.delete(stub, args) + } else if function == "query" { + // the old "Query" is now implemtned in invoke + return t.query(stub, args) + } + + return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"") +} + +// Transaction makes payment of X units from A to B +func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A, B string // Entities + var Aval, Bval int // Asset holdings + var X int // Transaction value + var err error + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + A = args[0] + B = args[1] + + // Get the state from the ledger + // TODO: will be nice to have a GetAllState call to ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + return shim.Error("Failed to get state") + } + if Avalbytes == nil { + return shim.Error("Entity not found") + } + Aval, _ = strconv.Atoi(string(Avalbytes)) + + Bvalbytes, err := stub.GetState(B) + if err != nil { + return shim.Error("Failed to get state") + } + if Bvalbytes == nil { + return shim.Error("Entity not found") + } + Bval, _ = strconv.Atoi(string(Bvalbytes)) + + // Perform the execution + X, err = strconv.Atoi(args[2]) + if err != nil { + return shim.Error("Invalid transaction amount, expecting a integer value") + } + Aval = Aval - X + Bval = Bval + X + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state back to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(nil) +} + +// Deletes an entity from state +func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + A := args[0] + + // Delete the key from the state in ledger + err := stub.DelState(A) + if err != nil { + return shim.Error("Failed to delete state") + } + + return shim.Success(nil) +} + +// query callback representing the query of a chaincode +func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A string // Entities + var err error + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting name of the person to query") + } + + A = args[0] + + // Get the state from the ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" + return shim.Error(jsonResp) + } + + if Avalbytes == nil { + jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" + return shim.Error(jsonResp) + } + + jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" + fmt.Printf("Query Response:%s\n", jsonResp) + return shim.Success(Avalbytes) +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +}