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 }