fabric-samples/chaincode/fabcar/go/contract/smartcontract.go
Brett Logan 23dc4e698a Add Tests to FabCar Go Chaincode
Many users raise questions on how to test chaincode. It used
to be much easier with the old shim, as they could directly
use the old mock stub in the shim. Now that it no longer exists
the fabcar example can provide an example of how to test chaincode.

Also worth noting is our current directory structure of our Go
chaincodes prevents the creation of mocks due to import cycles.
This change also pushes the chaincode logic down into a `contract`
package.

Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
2020-07-06 15:05:07 -04:00

127 lines
3.8 KiB
Go

package contract
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SmartContract provides functions for managing a car
type SmartContract struct {
contractapi.Contract
}
// Car describes basic details of what makes up a car
type Car struct {
Make string `json:"make"`
Model string `json:"model"`
Colour string `json:"colour"`
Owner string `json:"owner"`
}
// QueryResult structure used for handling result of query
type QueryResult struct {
Key string `json:"Key"`
Record *Car
}
// InitLedger adds a base set of cars to the ledger
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
cars := []Car{
{Make: "Toyota", Model: "Prius", Colour: "blue", Owner: "Tomoko"},
{Make: "Ford", Model: "Mustang", Colour: "red", Owner: "Brad"},
{Make: "Hyundai", Model: "Tucson", Colour: "green", Owner: "Jin Soo"},
{Make: "Volkswagen", Model: "Passat", Colour: "yellow", Owner: "Max"},
{Make: "Tesla", Model: "S", Colour: "black", Owner: "Adriana"},
{Make: "Peugeot", Model: "205", Colour: "purple", Owner: "Michel"},
{Make: "Chery", Model: "S22L", Colour: "white", Owner: "Aarav"},
{Make: "Fiat", Model: "Punto", Colour: "violet", Owner: "Pari"},
{Make: "Tata", Model: "Nano", Colour: "indigo", Owner: "Valeria"},
{Make: "Holden", Model: "Barina", Colour: "brown", Owner: "Shotaro"},
}
for i, car := range cars {
carAsBytes, _ := json.Marshal(car)
key := fmt.Sprintf("CAR%d", i)
err := ctx.GetStub().PutState(key, carAsBytes)
if err != nil {
return fmt.Errorf("failed to put to world state. %v", err)
}
}
return nil
}
// CreateCar adds a new car to the world state with given details
func (s *SmartContract) CreateCar(ctx contractapi.TransactionContextInterface, carNumber string, make string, model string, colour string, owner string) error {
car := Car{
Make: make,
Model: model,
Colour: colour,
Owner: owner,
}
carAsBytes, err := json.Marshal(car)
if err != nil {
return fmt.Errorf("failed marshalling to json: %v", err)
}
return ctx.GetStub().PutState(carNumber, carAsBytes)
}
// QueryCar returns the car stored in the world state with given id
func (s *SmartContract) QueryCar(ctx contractapi.TransactionContextInterface, carNumber string) (*Car, error) {
carAsBytes, err := ctx.GetStub().GetState(carNumber)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if carAsBytes == nil {
return nil, fmt.Errorf("%s does not exist", carNumber)
}
var car Car
err = json.Unmarshal(carAsBytes, &car)
if err != nil {
return nil, err
}
return &car, nil
}
// QueryAllCars returns all cars found in world state
func (s *SmartContract) QueryAllCars(ctx contractapi.TransactionContextInterface) ([]QueryResult, error) {
// Return all cars by using empty startKey and endKey
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()
var results []QueryResult
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
var car *Car
err = json.Unmarshal(queryResponse.Value, &car)
if err != nil {
return nil, fmt.Errorf("failed marshalling to json: %v", err)
}
queryResult := QueryResult{Key: queryResponse.Key, Record: car}
results = append(results, queryResult)
}
return results, nil
}
// ChangeCarOwner updates the owner field of car with given id in world state
func (s *SmartContract) ChangeCarOwner(ctx contractapi.TransactionContextInterface, carNumber string, newOwner string) error {
car, err := s.QueryCar(ctx, carNumber)
if err != nil {
return err
}
car.Owner = newOwner
carAsBytes, err := json.Marshal(car)
if err != nil {
return fmt.Errorf("failed marshalling to json: %v", err)
}
return ctx.GetStub().PutState(carNumber, carAsBytes)
}