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