github.com/altipla-consulting/ravendb-go-client@v0.1.3/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  }