github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/examples/ccchecker/ccchecker.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"sync"
    25  	"time"
    26  
    27  	"golang.org/x/net/context"
    28  
    29  	"github.com/hyperledger/fabric/examples/ccchecker/chaincodes"
    30  	"github.com/hyperledger/fabric/peer/common"
    31  )
    32  
    33  //global ccchecker params
    34  var ccchecker *CCChecker
    35  
    36  //CCChecker encapsulates ccchecker properties and runtime
    37  type CCChecker struct {
    38  	//Chaincodes to do ccchecker over (see ccchecker.json for defaults)
    39  	Chaincodes []*chaincodes.CCClient
    40  	//TimeoutToAbortSecs abort deadline
    41  	TimeoutToAbortSecs int
    42  	//ChainName name of the chain
    43  	ChainName string
    44  }
    45  
    46  //LoadCCCheckerParams read the ccchecker params from a file
    47  func LoadCCCheckerParams(file string) error {
    48  	var b []byte
    49  	var err error
    50  	if b, err = ioutil.ReadFile(file); err != nil {
    51  		return fmt.Errorf("Cannot read config file %s\n", err)
    52  	}
    53  	sp := &CCChecker{}
    54  	err = json.Unmarshal(b, &sp)
    55  	if err != nil {
    56  		return fmt.Errorf("error unmarshalling ccchecker: %s\n", err)
    57  	}
    58  
    59  	ccchecker = &CCChecker{}
    60  	id := 0
    61  	for _, scc := range sp.Chaincodes {
    62  		//concurrency <=0 will be dropped
    63  		if scc.Concurrency > 0 {
    64  			for i := 0; i < scc.Concurrency; i++ {
    65  				tmp := &chaincodes.CCClient{}
    66  				*tmp = *scc
    67  				tmp.ID = id
    68  				id = id + 1
    69  				ccchecker.Chaincodes = append(ccchecker.Chaincodes, tmp)
    70  			}
    71  		}
    72  	}
    73  
    74  	ccchecker.TimeoutToAbortSecs = sp.TimeoutToAbortSecs
    75  	ccchecker.ChainName = sp.ChainName
    76  
    77  	return nil
    78  }
    79  
    80  //CCCheckerInit assigns shadow chaincode to each of the CCClient from registered shadow chaincodes
    81  func CCCheckerInit() {
    82  	if ccchecker == nil {
    83  		fmt.Printf("LoadCCCheckerParams needs to be called before init\n")
    84  		os.Exit(1)
    85  	}
    86  
    87  	if err := chaincodes.RegisterCCClients(ccchecker.Chaincodes); err != nil {
    88  		panic(fmt.Sprintf("%s", err))
    89  	}
    90  }
    91  
    92  //CCCheckerRun main loops that will run the tests and cleanup
    93  func CCCheckerRun(orderingEndpoint string, report bool, verbose bool) error {
    94  	//connect with Broadcast client
    95  	bc, err := common.GetBroadcastClient(orderingEndpoint, false, "")
    96  	if err != nil {
    97  		return err
    98  	}
    99  	defer bc.Close()
   100  
   101  	ec, err := common.GetEndorserClient()
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	signer, err := common.GetDefaultSigner()
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	//when the wait's timeout and get out of ccchecker, we
   112  	//cancel and release all goroutines
   113  	ctxt, cancel := context.WithCancel(context.Background())
   114  	defer cancel()
   115  
   116  	var ccsWG sync.WaitGroup
   117  	ccsWG.Add(len(ccchecker.Chaincodes))
   118  
   119  	//an anonymous struct to hold failures
   120  	var failures struct {
   121  		sync.Mutex
   122  		failedCCClients int
   123  	}
   124  
   125  	//run the invokes
   126  	ccerrs := make([]error, len(ccchecker.Chaincodes))
   127  	for _, cc := range ccchecker.Chaincodes {
   128  		go func(cc2 *chaincodes.CCClient) {
   129  			if ccerrs[cc2.ID] = cc2.Run(ctxt, ccchecker.ChainName, bc, ec, signer, &ccsWG); ccerrs[cc2.ID] != nil {
   130  				failures.Lock()
   131  				failures.failedCCClients = failures.failedCCClients + 1
   132  				failures.Unlock()
   133  			}
   134  		}(cc)
   135  	}
   136  
   137  	//wait or timeout
   138  	err = ccchecker.wait(&ccsWG)
   139  
   140  	//verify results
   141  	if err == nil && failures.failedCCClients < len(ccchecker.Chaincodes) {
   142  		ccsWG = sync.WaitGroup{}
   143  		ccsWG.Add(len(ccchecker.Chaincodes) - failures.failedCCClients)
   144  		for _, cc := range ccchecker.Chaincodes {
   145  			go func(cc2 *chaincodes.CCClient) {
   146  				if ccerrs[cc2.ID] == nil {
   147  					ccerrs[cc2.ID] = cc2.Validate(ctxt, ccchecker.ChainName, bc, ec, signer, &ccsWG)
   148  				} else {
   149  					fmt.Printf("Ignoring [%v] for validation as it returned err %s\n", cc2, ccerrs[cc2.ID])
   150  				}
   151  			}(cc)
   152  		}
   153  
   154  		//wait or timeout
   155  		err = ccchecker.wait(&ccsWG)
   156  	}
   157  
   158  	if report {
   159  		for _, cc := range ccchecker.Chaincodes {
   160  			cc.Report(verbose, ccchecker.ChainName)
   161  		}
   162  	}
   163  
   164  	return err
   165  }
   166  
   167  func (s *CCChecker) wait(ccsWG *sync.WaitGroup) error {
   168  	done := make(chan struct{})
   169  	go func() {
   170  		ccsWG.Wait()
   171  		done <- struct{}{}
   172  	}()
   173  	select {
   174  	case <-done:
   175  		return nil
   176  	case <-time.After(time.Duration(s.TimeoutToAbortSecs) * time.Second):
   177  		return fmt.Errorf("Aborting due to timeoutout!!")
   178  	}
   179  }