github.com/canhui/fabric_ca2_2@v2.0.0-alpha+incompatible/test/fabric-ca-load-tester/main.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 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  package main
    17  
    18  import (
    19  	"crypto/rand"
    20  	"flag"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"log"
    24  	"net/url"
    25  	"os"
    26  	"path/filepath"
    27  	"sync"
    28  	"time"
    29  
    30  	"github.com/hyperledger/fabric-ca/api"
    31  	"github.com/hyperledger/fabric-ca/lib"
    32  	yaml "gopkg.in/yaml.v2"
    33  )
    34  
    35  // IdentityType represents type of identity in the fabric
    36  type IdentityType string
    37  
    38  const (
    39  	// User user identity type
    40  	User IdentityType = "User"
    41  	// Peer peer identity type
    42  	Peer = "Peer"
    43  	// Validator validator identity type
    44  	Validator = "Validator"
    45  )
    46  
    47  // TestRequest represents request properties from
    48  // which a request payload object can be constructed
    49  type TestRequest map[string]interface{}
    50  
    51  // Test represents a fabric-ca test
    52  type Test struct {
    53  	Name   string      `yaml:"name"`
    54  	Repeat int         `yaml:"repeat,omitempty"`
    55  	Req    TestRequest `yaml:"req,omitempty"`
    56  }
    57  
    58  type testConfig struct {
    59  	ServerURL      string           `yaml:"serverURL"`
    60  	ConfigHome     string           `yaml:"caConfigHome"`
    61  	NumUsers       int              `yaml:"numClients"`
    62  	NumReqsPerUser int              `yaml:"numReqsPerClient"`
    63  	TestSeq        []Test           `yaml:"testSeq"`
    64  	Affiliation    string           `yaml:"affiliation"`
    65  	CAClientConfig lib.ClientConfig `yaml:"caClientConfig"`
    66  }
    67  
    68  // enrollmentID encapsulates an identity's name and type
    69  type enrollmentID struct {
    70  	ID *string
    71  	it *IdentityType
    72  }
    73  
    74  var (
    75  	testCfg     testConfig
    76  	testCfgFile *string
    77  )
    78  
    79  func main() {
    80  	t0 := time.Now()
    81  	testCfgFile = flag.String("config", "testConfig.yml", "Fully qualified name of the test configuration file")
    82  	flag.Parse()
    83  
    84  	// Create CA client config
    85  	err := readConfig()
    86  	if err != nil {
    87  		log.Printf("Failed to create client config: %v", err)
    88  		return
    89  	}
    90  
    91  	// Enroll boostrap user
    92  	bootID, err1 := enrollBootstrapUser(&testCfg.ServerURL,
    93  		&testCfg.ConfigHome, &testCfg.CAClientConfig)
    94  	if err1 != nil {
    95  		log.Printf("Failed to enroll bootstrap user: %v", err1)
    96  		return
    97  	}
    98  
    99  	fin := make(chan testClientRes, testCfg.NumUsers)
   100  
   101  	var wg sync.WaitGroup
   102  	for i := 0; i < testCfg.NumUsers; i++ {
   103  		c := getTestClient(i, &testCfg.ConfigHome, &testCfg.CAClientConfig, bootID)
   104  		if err != nil {
   105  			log.Printf("Failed to get client: %v", err)
   106  			continue
   107  		}
   108  		// Increment the WaitGroup counter
   109  		wg.Add(1)
   110  		go func() {
   111  			// Decrement the counter when the goroutine completes
   112  			defer wg.Done()
   113  			c.runTests(fin)
   114  		}()
   115  	}
   116  	wg.Wait()
   117  	t1 := time.Now()
   118  	log.Printf("Load test finished in %v seconds\n", t1.Sub(t0).Seconds())
   119  	for i := 0; i < testCfg.NumUsers; i++ {
   120  		log.Println(<-fin)
   121  	}
   122  }
   123  
   124  // Enrolls bootstrap user and sets the cfg global object
   125  func enrollBootstrapUser(surl *string, configHome *string,
   126  	cfg *lib.ClientConfig) (id *lib.Identity, err error) {
   127  	var resp *lib.EnrollmentResponse
   128  	resp, err = cfg.Enroll(*surl, *configHome)
   129  	if err != nil {
   130  		log.Printf("Enrollment of boostrap user failed: %v", err)
   131  		return id, err
   132  	}
   133  	log.Printf("Successfully enrolled boostrap user")
   134  
   135  	id = resp.Identity
   136  	cfg.ID.Name = id.GetName()
   137  	return id, err
   138  }
   139  
   140  // Reads test config
   141  func readConfig() error {
   142  	tcFile, e := ioutil.ReadFile(*testCfgFile)
   143  	if e != nil {
   144  		log.Printf("Failed to read configuration file '%s': %v", *testCfgFile, e)
   145  		os.Exit(1)
   146  	}
   147  	yaml.Unmarshal(tcFile, &testCfg)
   148  
   149  	uo, err := url.Parse(testCfg.ServerURL)
   150  	if err != nil {
   151  		return err
   152  	}
   153  	u := fmt.Sprintf("%s://%s", uo.Scheme, uo.Host)
   154  	testCfg.CAClientConfig.URL = u
   155  
   156  	// Make config home absolute
   157  	if !filepath.IsAbs(testCfg.ConfigHome) {
   158  		testCfg.ConfigHome, err = filepath.Abs(testCfg.ConfigHome)
   159  		if err != nil {
   160  			log.Printf("Failed to get full path of config file: %s", err)
   161  		}
   162  	}
   163  
   164  	log.Printf("Config created: %+v", testCfg)
   165  	return nil
   166  }
   167  
   168  // Returns a random affiliation
   169  func getAffiliation() string {
   170  	return testCfg.Affiliation
   171  }
   172  
   173  // Returns a random enrollment ID
   174  func genEnrollmentID(it IdentityType) (eid *enrollmentID, err error) {
   175  	b := make([]byte, 16)
   176  	_, err = rand.Read(b)
   177  	if err != nil {
   178  		return
   179  	}
   180  	uuid := fmt.Sprintf("%s-%X-%X-%X-%X-%X", it, b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
   181  	eid = &enrollmentID{
   182  		ID: &uuid,
   183  		it: &it,
   184  	}
   185  	return
   186  }
   187  
   188  // Returns identity type based on the value of i
   189  func getIdentityType(i int) IdentityType {
   190  	tipe := i % 3
   191  	switch tipe {
   192  	case 0:
   193  		return User
   194  	case 1:
   195  		return Peer
   196  	case 2:
   197  		return Validator
   198  	default:
   199  		return User
   200  	}
   201  }
   202  
   203  func (tr TestRequest) getTCertsReq() *api.GetTCertBatchRequest {
   204  	count := tr["count"].(int)
   205  	prekey := tr["prekey"].(string)
   206  	disableKdf := tr["disable_kdf"].(bool)
   207  	encryptAttrs := tr["encrypt_attrs"].(bool)
   208  	return &api.GetTCertBatchRequest{
   209  		Count:                count,
   210  		PreKey:               prekey,
   211  		DisableKeyDerivation: disableKdf,
   212  		EncryptAttrs:         encryptAttrs,
   213  	}
   214  }
   215  
   216  func (tr TestRequest) getEnrollmentReq() *api.EnrollmentRequest {
   217  	name := tr["name"].(string)
   218  	pass := tr["pass"].(string)
   219  	return &api.EnrollmentRequest{
   220  		Name:   name,
   221  		Secret: pass,
   222  	}
   223  }