github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/tests/util_test.go (about) 1 package tests 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/rsa" 7 "crypto/tls" 8 "crypto/x509" 9 "encoding/json" 10 "encoding/pem" 11 "fmt" 12 "io/ioutil" 13 "net" 14 "net/http" 15 "os" 16 "runtime" 17 "sort" 18 "strconv" 19 "strings" 20 "time" 21 ) 22 23 const ( 24 unlikelySep = "\x02\x01\x03" 25 ) 26 27 func stringArrayCopy(a []string) []string { 28 if len(a) == 0 { 29 return nil 30 } 31 return append([]string{}, a...) 32 } 33 34 func stringArrayContains(a []string, s string) bool { 35 for _, el := range a { 36 if el == s { 37 return true 38 } 39 } 40 return false 41 } 42 43 // equivalent of Java's containsSequence http://joel-costigliola.github.io/assertj/core/api/org/assertj/core/api/ListAssert.html#containsSequence(ELEMENT...) 44 // checks if a1 contains sub-sequence a2 45 func stringArrayContainsSequence(a1, a2 []string) bool { 46 // TODO: technically it's possible for this to have false positive 47 // but it's very unlikely 48 s1 := strings.Join(a1, unlikelySep) 49 s2 := strings.Join(a2, unlikelySep) 50 return strings.Contains(s1, s2) 51 } 52 53 func stringArrayContainsExactly(a1, a2 []string) bool { 54 if len(a1) != len(a2) { 55 return false 56 } 57 for i, s := range a1 { 58 if s != a2[i] { 59 return false 60 } 61 } 62 return true 63 } 64 65 // stringArrayEq returns true if arrays have the same content, ignoring order 66 func stringArrayEq(a1, a2 []string) bool { 67 if len(a1) != len(a2) { 68 return false 69 } 70 if len(a1) == 0 { 71 return true 72 } 73 a1c := stringArrayCopy(a1) 74 a2c := stringArrayCopy(a2) 75 sort.Strings(a1c) 76 sort.Strings(a2c) 77 for i, s := range a1c { 78 if s != a2c[i] { 79 return false 80 } 81 } 82 return true 83 } 84 85 func stringArrayReverse(a []string) { 86 n := len(a) 87 for i := 0; i < n/2; i++ { 88 a[i], a[n-1-i] = a[n-1-i], a[i] 89 } 90 } 91 92 func int64ArrayHasDuplicates(a []int64) bool { 93 if len(a) == 0 { 94 return false 95 } 96 m := map[int64]int{} 97 for _, i := range a { 98 m[i]++ 99 if m[i] > 1 { 100 return true 101 } 102 } 103 return false 104 } 105 106 func jsonGetAsText(doc map[string]interface{}, key string) (string, bool) { 107 v, ok := doc[key] 108 if !ok { 109 return "", false 110 } 111 s, ok := v.(string) 112 if !ok { 113 return "", false 114 } 115 return s, true 116 } 117 118 func objectNodeFieldNames(js map[string]interface{}) []string { 119 var res []string 120 for k := range js { 121 res = append(res, k) 122 } 123 return res 124 } 125 126 func isUnprintable(c byte) bool { 127 if c < 32 { 128 // 9 - tab, 10 - LF, 13 - CR 129 if c == 9 || c == 10 || c == 13 { 130 return false 131 } 132 return true 133 } 134 return c >= 127 135 } 136 137 func isBinaryData(d []byte) bool { 138 for _, b := range d { 139 if isUnprintable(b) { 140 return true 141 } 142 } 143 return false 144 } 145 146 func asHex(d []byte) ([]byte, bool) { 147 if !isBinaryData(d) { 148 return d, false 149 } 150 151 // convert unprintable characters to hex 152 var res []byte 153 for i, c := range d { 154 if i > 2048 { 155 break 156 } 157 if isUnprintable(c) { 158 s := fmt.Sprintf("x%02x ", c) 159 res = append(res, s...) 160 } else { 161 res = append(res, c) 162 } 163 } 164 return res, true 165 } 166 167 func isEnvVarTrue(name string) bool { 168 v := strings.TrimSpace(strings.ToLower(os.Getenv(name))) 169 switch v { 170 case "yes", "true": 171 return true 172 } 173 return false 174 } 175 176 // if d is a valid json, pretty-print it 177 // only used for debugging 178 func maybePrettyPrintJSON(d []byte) []byte { 179 if d2, ok := asHex(d); ok { 180 return d2 181 } 182 var m map[string]interface{} 183 err := json.Unmarshal(d, &m) 184 if err != nil { 185 return d 186 } 187 d2, err := json.MarshalIndent(m, "", " ") 188 if err != nil { 189 return d 190 } 191 return d2 192 } 193 194 func fileExists(path string) bool { 195 st, err := os.Lstat(path) 196 return err == nil && !st.IsDir() 197 } 198 199 func isWindows() bool { 200 return runtime.GOOS == "windows" 201 } 202 203 func timeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) { 204 return func(netw, addr string) (net.Conn, error) { 205 conn, err := net.DialTimeout(netw, addr, cTimeout) 206 if err != nil { 207 return nil, err 208 } 209 conn.SetDeadline(time.Now().Add(rwTimeout)) 210 return conn, nil 211 } 212 } 213 214 // can be used for http.Get() requests with better timeouts. New one must be created 215 // for each Get() request 216 func newTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client { 217 return &http.Client{ 218 Transport: &http.Transport{ 219 Dial: timeoutDialer(connectTimeout, readWriteTimeout), 220 Proxy: http.ProxyFromEnvironment, 221 }, 222 } 223 } 224 225 var ( 226 defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36" 227 ) 228 229 func downloadURL(url string) ([]byte, error) { 230 // default timeout for http.Get() is really long, so dial it down 231 // for both connection and read/write timeouts 232 timeoutClient := newTimeoutClient(time.Second*120, time.Second*120) 233 req, err := http.NewRequest(http.MethodGet, url, nil) 234 if err != nil { 235 return nil, err 236 } 237 req.Header.Set("User-Agent", defaultUserAgent) 238 resp, err := timeoutClient.Do(req) 239 if err != nil { 240 return nil, err 241 } 242 defer resp.Body.Close() 243 if resp.StatusCode != 200 { 244 return nil, fmt.Errorf("'%s': status code not 200 (%d)", url, resp.StatusCode) 245 } 246 return ioutil.ReadAll(resp.Body) 247 } 248 249 func httpDl(url string, destPath string) error { 250 d, err := downloadURL(url) 251 if err != nil { 252 return err 253 } 254 return ioutil.WriteFile(destPath, d, 0755) 255 } 256 257 func getProcessId() string { 258 pid := os.Getpid() 259 return strconv.Itoa(pid) 260 } 261 262 func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { 263 if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { 264 return key, nil 265 } 266 if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { 267 switch key := key.(type) { 268 case *rsa.PrivateKey, *ecdsa.PrivateKey: 269 return key, nil 270 default: 271 return nil, fmt.Errorf("Found unknown private key type in PKCS#8 wrapping") 272 } 273 } 274 if key, err := x509.ParseECPrivateKey(der); err == nil { 275 return key, nil 276 } 277 return nil, fmt.Errorf("Failed to parse private key") 278 } 279 280 // TODO: expose this in the library as a helper function 281 func loadCertficateAndKeyFromFile(path string) (*tls.Certificate, error) { 282 raw, err := ioutil.ReadFile(path) 283 if err != nil { 284 return nil, err 285 } 286 287 var cert tls.Certificate 288 for { 289 block, rest := pem.Decode(raw) 290 if block == nil { 291 break 292 } 293 if block.Type == "CERTIFICATE" { 294 cert.Certificate = append(cert.Certificate, block.Bytes) 295 } else { 296 cert.PrivateKey, err = parsePrivateKey(block.Bytes) 297 if err != nil { 298 return nil, fmt.Errorf("Failure reading private key from \"%s\": %s", path, err) 299 } 300 } 301 raw = rest 302 } 303 304 if len(cert.Certificate) == 0 { 305 return nil, fmt.Errorf("No certificate found in \"%s\"", path) 306 } else if cert.PrivateKey == nil { 307 return nil, fmt.Errorf("No private key found in \"%s\"", path) 308 } 309 310 return &cert, nil 311 } 312 313 func entityToDocument(e interface{}) (map[string]interface{}, error) { 314 js, err := json.Marshal(e) 315 if err != nil { 316 return nil, err 317 } 318 var doc map[string]interface{} 319 err = json.Unmarshal(js, &doc) 320 if err != nil { 321 return nil, err 322 } 323 return doc, nil 324 }