Skip to content

Commit

Permalink
FAB-1497 sundry changes in prep for moving ccchecker
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1497

Some name changes and provide more info to the shadow.

Change-Id: Ie058ded0339956aa871e4da90301777242110691
Signed-off-by: Srinivasan Muralidharan <[email protected]>
  • Loading branch information
Srinivasan Muralidharan committed Jan 1, 2017
1 parent 151e6ac commit aba0358
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 45 deletions.
20 changes: 10 additions & 10 deletions examples/ccchecker/ccchecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var ccchecker *CCChecker
//CCChecker encapsulates ccchecker properties and runtime
type CCChecker struct {
//Chaincodes to do ccchecker over (see ccchecker.json for defaults)
Chaincodes []*chaincodes.CC
Chaincodes []*chaincodes.CCClient
//TimeoutToAbortSecs abort deadline
TimeoutToAbortSecs int
//ChainName name of the chain
Expand All @@ -62,7 +62,7 @@ func LoadCCCheckerParams(file string) error {
//concurrency <=0 will be dropped
if scc.Concurrency > 0 {
for i := 0; i < scc.Concurrency; i++ {
tmp := &chaincodes.CC{}
tmp := &chaincodes.CCClient{}
*tmp = *scc
tmp.ID = id
id = id + 1
Expand All @@ -77,14 +77,14 @@ func LoadCCCheckerParams(file string) error {
return nil
}

//CCCheckerInit assigns shadow chaincode to each of the CC from registered shadow chaincodes
//CCCheckerInit assigns shadow chaincode to each of the CCClient from registered shadow chaincodes
func CCCheckerInit() {
if ccchecker == nil {
fmt.Printf("LoadCCCheckerParams needs to be called before init\n")
os.Exit(1)
}

if err := chaincodes.RegisterCCs(ccchecker.Chaincodes); err != nil {
if err := chaincodes.RegisterCCClients(ccchecker.Chaincodes); err != nil {
panic(fmt.Sprintf("%s", err))
}
}
Expand Down Expand Up @@ -119,16 +119,16 @@ func CCCheckerRun(report bool, verbose bool) error {
//an anonymous struct to hold failures
var failures struct {
sync.Mutex
failedCCs int
failedCCClients int
}

//run the invokes
ccerrs := make([]error, len(ccchecker.Chaincodes))
for _, cc := range ccchecker.Chaincodes {
go func(cc2 *chaincodes.CC) {
go func(cc2 *chaincodes.CCClient) {
if ccerrs[cc2.ID] = cc2.Run(ctxt, ccchecker.ChainName, bc, ec, signer, &ccsWG); ccerrs[cc2.ID] != nil {
failures.Lock()
failures.failedCCs = failures.failedCCs + 1
failures.failedCCClients = failures.failedCCClients + 1
failures.Unlock()
}
}(cc)
Expand All @@ -138,11 +138,11 @@ func CCCheckerRun(report bool, verbose bool) error {
err = ccchecker.wait(&ccsWG)

//verify results
if err == nil && failures.failedCCs < len(ccchecker.Chaincodes) {
if err == nil && failures.failedCCClients < len(ccchecker.Chaincodes) {
ccsWG = sync.WaitGroup{}
ccsWG.Add(len(ccchecker.Chaincodes) - failures.failedCCs)
ccsWG.Add(len(ccchecker.Chaincodes) - failures.failedCCClients)
for _, cc := range ccchecker.Chaincodes {
go func(cc2 *chaincodes.CC) {
go func(cc2 *chaincodes.CCClient) {
if ccerrs[cc2.ID] == nil {
ccerrs[cc2.ID] = cc2.Validate(ctxt, ccchecker.ChainName, bc, ec, signer, &ccsWG)
} else {
Expand Down
3 changes: 2 additions & 1 deletion examples/ccchecker/ccchecker.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{"Chaincodes":
[
{"Name": "mycc",
"InitArgs":[""],
"Path": "github.com/hyperledger/fabric/examples/ccchecker/chaincodes/newkeyperinvoke",
"NumFinalQueryAttempts": 10,
"NumberOfIterations": 10,
"NumberOfInvokes": 10,
"DelayBetweenInvokeMs": 1,
"DelayBetweenQueryMs": 10,
"TimeoutToAbortSecs": 60,
Expand Down
64 changes: 43 additions & 21 deletions examples/ccchecker/chaincodes/chaincodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
//ShadowCCIntf interfaces to be implemented by shadow chaincodes
type ShadowCCIntf interface {
//InitShadowCC initializes the shadow chaincode (will be called once for each chaincode)
InitShadowCC()
InitShadowCC(initArgs []string)

//GetInvokeArgs gets invoke arguments from shadow
GetInvokeArgs(ccnum int, iter int) [][]byte
Expand All @@ -45,22 +45,31 @@ type ShadowCCIntf interface {

//Validate the results against the query arguments
Validate(args [][]byte, value []byte) error

//GetNumQueries returns number of queries to perform
GetNumQueries(numSuccessfulInvokes int) int

//OverrideNumInvokes overrides the users number of invoke request
OverrideNumInvokes(numInvokesPlanned int) int
}

//CC chaincode properties, config and runtime
type CC struct {
//CCClient chaincode properties, config and runtime
type CCClient struct {
//-------------config properties ------------
//Name of the chaincode
Name string

//InitArgs used for deploying the chaincode
InitArgs []string

//Path to the chaincode
Path string

//NumFinalQueryAttempts number of times to try final query before giving up
NumFinalQueryAttempts int

//NumberOfInvokeIterations number of iterations to do invoke on
NumberOfIterations int
//NumberOfInvokes number of iterations to do invoke on
NumberOfInvokes int

//DelayBetweenInvokeMs delay between each invoke
DelayBetweenInvokeMs int
Expand All @@ -87,14 +96,22 @@ type CC struct {
//shadow CC where the chaincode stats is maintained
shadowCC ShadowCCIntf

//number of iterations a shadow cc actually wants
//this could be different from NumberOfInvokes
overriddenNumInvokes int

//numer of queries to perform
//retrieved from the shadow CC
numQueries int

//current iteration of invoke
currentInvokeIter int

//start of invokes in epoch seconds
invokeStartTime int
invokeStartTime int64

//end of invokes in epoch seconds
invokeEndTime int
invokeEndTime int64

//error that stopped invoke iterations
invokeErr error
Expand All @@ -109,7 +126,7 @@ type CC struct {
queryErrs []error
}

func (cc *CC) getChaincodeSpec(args [][]byte) *pb.ChaincodeSpec {
func (cc *CCClient) getChaincodeSpec(args [][]byte) *pb.ChaincodeSpec {
return &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[cc.Lang]),
ChaincodeID: &pb.ChaincodeID{Path: cc.Path, Name: cc.Name},
Expand All @@ -120,12 +137,15 @@ func (cc *CC) getChaincodeSpec(args [][]byte) *pb.ChaincodeSpec {
//doInvokes calls invoke for each iteration for the chaincode
//Stops at the first invoke with error
//currentInvokeIter contains the number of successful iterations
func (cc *CC) doInvokes(ctxt context.Context, chainID string,
func (cc *CCClient) doInvokes(ctxt context.Context, chainID string,
bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity,
wg *sync.WaitGroup, quit func() bool) error {

//perhaps the shadow CC wants to override the number of iterations
cc.overriddenNumInvokes = cc.shadowCC.OverrideNumInvokes(cc.NumberOfInvokes)

var err error
for cc.currentInvokeIter = 0; cc.currentInvokeIter < cc.NumberOfIterations; cc.currentInvokeIter++ {
for cc.currentInvokeIter = 0; cc.currentInvokeIter < cc.overriddenNumInvokes; cc.currentInvokeIter++ {
if quit() {
break
}
Expand Down Expand Up @@ -154,7 +174,7 @@ func (cc *CC) doInvokes(ctxt context.Context, chainID string,
}

//don't sleep for the last iter
if cc.DelayBetweenInvokeMs > 0 && cc.currentInvokeIter < (cc.NumberOfIterations-1) {
if cc.DelayBetweenInvokeMs > 0 && cc.currentInvokeIter < (cc.overriddenNumInvokes-1) {
time.Sleep(time.Duration(cc.DelayBetweenInvokeMs) * time.Millisecond)
}
}
Expand All @@ -165,7 +185,7 @@ func (cc *CC) doInvokes(ctxt context.Context, chainID string,
//Run test over given number of iterations
// i will be unique across chaincodes and can be used as a key
// this is useful if chaincode occurs multiple times in the array of chaincodes
func (cc *CC) Run(ctxt context.Context, chainID string, bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity, wg *sync.WaitGroup) error {
func (cc *CCClient) Run(ctxt context.Context, chainID string, bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity, wg *sync.WaitGroup) error {
defer wg.Done()

var (
Expand All @@ -181,12 +201,12 @@ func (cc *CC) Run(ctxt context.Context, chainID string, bc common.BroadcastClien
quitF := func() bool { return quit }

//start of invokes
cc.invokeStartTime = time.Now().Second()
cc.invokeStartTime = time.Now().UnixNano() / 1000000

err = cc.doInvokes(ctxt, chainID, bc, ec, signer, wg, quitF)

//end of invokes
cc.invokeEndTime = time.Now().Second()
cc.invokeEndTime = time.Now().UnixNano() / 1000000
}()

//we could be done or cancelled or timedout
Expand All @@ -203,7 +223,7 @@ func (cc *CC) Run(ctxt context.Context, chainID string, bc common.BroadcastClien
}

//validates the invoke iteration for this chaincode
func (cc *CC) validateIter(ctxt context.Context, iter int, chainID string, bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity, wg *sync.WaitGroup, quit func() bool) {
func (cc *CCClient) validateIter(ctxt context.Context, iter int, chainID string, bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity, wg *sync.WaitGroup, quit func() bool) {
defer wg.Done()
args := cc.shadowCC.GetQueryArgs(cc.ID, iter)

Expand Down Expand Up @@ -253,7 +273,7 @@ func (cc *CC) validateIter(ctxt context.Context, iter int, chainID string, bc co
}

//Validate test that was Run. Each successful iteration in the run is validated against
func (cc *CC) Validate(ctxt context.Context, chainID string, bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity, wg *sync.WaitGroup) error {
func (cc *CCClient) Validate(ctxt context.Context, chainID string, bc common.BroadcastClient, ec pb.EndorserClient, signer msp.SigningIdentity, wg *sync.WaitGroup) error {
defer wg.Done()

//this will signal inner validators to get out via
Expand All @@ -280,8 +300,10 @@ func (cc *CC) Validate(ctxt context.Context, chainID string, bc common.Broadcast
//return the quit closure for validation within validateIter
quitF := func() bool { return quit }

cc.numQueries = cc.shadowCC.GetNumQueries(cc.currentInvokeIter)

//try only till successful invoke iterations
for i := 0; i < cc.currentInvokeIter; i++ {
for i := 0; i < cc.numQueries; i++ {
go func(iter int) {
cc.validateIter(ctxt, iter, chainID, bc, ec, signer, &innerwg, quitF)
}(i)
Expand Down Expand Up @@ -317,22 +339,22 @@ func (cc *CC) Validate(ctxt context.Context, chainID string, bc common.Broadcast
}

//Report reports chaincode test execution, iter by iter
func (cc *CC) Report(verbose bool, chainID string) {
func (cc *CCClient) Report(verbose bool, chainID string) {
fmt.Printf("%s/%s(%d)\n", cc.Name, chainID, cc.ID)
fmt.Printf("\tNum successful invokes: %d(%d)\n", cc.currentInvokeIter, cc.NumberOfIterations)
fmt.Printf("\tNum successful invokes: %d(%d,%d)\n", cc.currentInvokeIter, cc.NumberOfInvokes, cc.overriddenNumInvokes)
if cc.invokeErr != nil {
fmt.Printf("\tError on invoke: %s\n", cc.invokeErr)
}
//test to see if validate was called (validate alloc the arrays, one of which is queryWorked)
if cc.queryWorked != nil {
for i := 0; i < cc.currentInvokeIter; i++ {
for i := 0; i < cc.numQueries; i++ {
fmt.Printf("\tQuery(%d) : succeeded-%t, num trials-%d(%d), error if any(%s)\n", i, cc.queryWorked[i], cc.currQueryIter[i], cc.NumFinalQueryAttempts, cc.queryErrs[i])
}
} else {
fmt.Printf("\tQuery validation appears not have been performed(#invokes-%d). timed out ?\n", cc.currentInvokeIter)
}
//total actual time for cc.currentInvokeIter
invokeTime := (cc.invokeEndTime-cc.invokeStartTime)*1000 - (cc.DelayBetweenInvokeMs * (cc.currentInvokeIter - 1))
invokeTime := cc.invokeEndTime - cc.invokeStartTime - int64(cc.DelayBetweenInvokeMs*(cc.currentInvokeIter-1))
fmt.Printf("\tTime for invokes(ms): %d\n", invokeTime)

fmt.Printf("\tFinal query worked ? %t\n", cc.queryWorked)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ type NewKeyPerInvoke struct {
//---------- implements ShadowCCIntf functions -------

//InitShadowCC initializes CC
func (t *NewKeyPerInvoke) InitShadowCC() {
func (t *NewKeyPerInvoke) InitShadowCC(initArgs []string) {
t.state = make(map[string][]byte)
}

//setState sets the state
func (t *NewKeyPerInvoke) setState(key []byte, val []byte) {
//invokeSuccessful sets the state and increments succefull invokes counter
func (t *NewKeyPerInvoke) invokeSuccessful(key []byte, val []byte) {
t.Lock()
defer t.Unlock()
t.state[string(key)] = val
t.Unlock()
}

//getState gets the state
Expand All @@ -52,6 +52,18 @@ func (t *NewKeyPerInvoke) getState(key []byte) ([]byte, bool) {
return v, ok
}

//OverrideNumInvokes returns the number of invokes shadow wants
//accept users request, no override
func (t *NewKeyPerInvoke) OverrideNumInvokes(numInvokesPlanned int) int {
return numInvokesPlanned
}

//GetNumQueries returns the number of queries shadow wants ccchecked to do.
//For our purpose, just do as many queries as there were invokes for.
func (t *NewKeyPerInvoke) GetNumQueries(numInvokesCompletedSuccessfully int) int {
return numInvokesCompletedSuccessfully
}

//GetInvokeArgs get args for invoke based on chaincode ID and iteration num
func (t *NewKeyPerInvoke) GetInvokeArgs(ccnum int, iter int) [][]byte {
args := make([][]byte, 3)
Expand All @@ -77,7 +89,7 @@ func (t *NewKeyPerInvoke) PostInvoke(args [][]byte, resp []byte) error {
return fmt.Errorf("invalid response %s", string(resp))
}

t.setState(args[1], args[2])
t.invokeSuccessful(args[1], args[2])

return nil
}
Expand Down
30 changes: 22 additions & 8 deletions examples/ccchecker/chaincodes/registershadow.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,39 @@ var shadowCCs = map[string]ShadowCCIntf{
"github.com/hyperledger/fabric/examples/ccchecker/chaincodes/newkeyperinvoke": &nkpi.NewKeyPerInvoke{},
}

//RegisterCCs registers all possible chaincodes that can be used in test
func RegisterCCs(ccs []*CC) error {
inUse := make(map[string]ShadowCCIntf)
type shadowCCArgs struct {
initArgs []string
}

//For each chaincode that's deployed corresdponds a shadowCC. Not all
//shadows in shadowCCs maybe used in a run using the input JSON. And each
//chaincode maybe used multiple times (either because Concurrency is > 1 or
//the chaincode is used multiple times in the JSON with different CCChecker
//parameters). inUseShadowCCs keeps a set of all shadow CCs in use
var inUseShadowCCs map[ShadowCCIntf]*shadowCCArgs

//RegisterCCClients registers and maps chaincode clients to their shadows
func RegisterCCClients(ccs []*CCClient) error {
inUseShadowCCs = make(map[ShadowCCIntf]*shadowCCArgs)
for _, cc := range ccs {
scc, ok := shadowCCs[cc.Path]
if !ok || scc == nil {
return fmt.Errorf("%s not a registered chaincode", cc.Path)
}
if _, ok := inUse[cc.Path]; !ok {
inUse[cc.Path] = scc
}

//setup the shadow chaincode to plug into the ccchecker framework
cc.shadowCC = scc

//add cc to the list in shadow cc
if _, ok := inUseShadowCCs[scc]; !ok {
inUseShadowCCs[scc] = &shadowCCArgs{cc.InitArgs}
}
}

//initialize a shadow chaincode just once. A chaincode may be used
//multiple times in test run
for _, cc := range inUse {
cc.InitShadowCC()
for scc, sccArgs := range inUseShadowCCs {
scc.InitShadowCC(sccArgs.initArgs)
}

return nil
Expand Down

0 comments on commit aba0358

Please sign in to comment.