github.com/opensearch-project/opensearch-go/v2@v2.3.0/opensearch_integration_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // 3 // The OpenSearch Contributors require contributions made to 4 // this file be licensed under the Apache-2.0 license or a 5 // compatible open source license. 6 // 7 // Modifications Copyright OpenSearch Contributors. See 8 // GitHub history for details. 9 10 // Licensed to Elasticsearch B.V. under one or more contributor 11 // license agreements. See the NOTICE file distributed with 12 // this work for additional information regarding copyright 13 // ownership. Elasticsearch B.V. licenses this file to you under 14 // the Apache License, Version 2.0 (the "License"); you may 15 // not use this file except in compliance with the License. 16 // You may obtain a copy of the License at 17 // 18 // http://www.apache.org/licenses/LICENSE-2.0 19 // 20 // Unless required by applicable law or agreed to in writing, 21 // software distributed under the License is distributed on an 22 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 23 // KIND, either express or implied. See the License for the 24 // specific language governing permissions and limitations 25 // under the License. 26 27 // +build integration,!multinode 28 29 package opensearch_test 30 31 import ( 32 "context" 33 "crypto/tls" 34 "encoding/json" 35 "log" 36 "net" 37 "net/http" 38 "net/url" 39 "sync" 40 "sync/atomic" 41 "testing" 42 "time" 43 44 "github.com/opensearch-project/opensearch-go/v2" 45 "github.com/opensearch-project/opensearch-go/v2/opensearchapi" 46 "github.com/opensearch-project/opensearch-go/v2/opensearchtransport" 47 ) 48 49 func TestClientTransport(t *testing.T) { 50 t.Run("Persistent", func(t *testing.T) { 51 client, err := opensearch.NewDefaultClient() 52 if err != nil { 53 t.Fatalf("Error creating the client: %s", err) 54 } 55 56 var total int 57 58 for i := 0; i < 101; i++ { 59 var curTotal int 60 61 res, err := client.Nodes.Stats(client.Nodes.Stats.WithMetric("http")) 62 if err != nil { 63 t.Fatalf("Unexpected error: %s", err) 64 } 65 defer res.Body.Close() 66 67 r := struct { 68 Nodes map[string]struct { 69 HTTP struct { 70 TotalOpened int `json:"total_opened"` 71 } 72 } 73 }{} 74 75 if err := json.NewDecoder(res.Body).Decode(&r); err != nil { 76 t.Fatalf("Error parsing the response body: %s", err) 77 } 78 79 for _, v := range r.Nodes { 80 curTotal = v.HTTP.TotalOpened 81 break 82 } 83 84 if curTotal < 1 { 85 t.Errorf("Unexpected total_opened: %d", curTotal) 86 } 87 88 if total == 0 { 89 total = curTotal 90 } 91 92 if total != curTotal { 93 t.Errorf("Expected total_opened=%d, got: %d", total, curTotal) 94 } 95 } 96 97 log.Printf("total_opened: %d", total) 98 }) 99 100 t.Run("Concurrent", func(t *testing.T) { 101 var wg sync.WaitGroup 102 103 client, err := opensearch.NewDefaultClient() 104 if err != nil { 105 t.Fatalf("Error creating the client: %s", err) 106 } 107 108 for i := 0; i < 101; i++ { 109 wg.Add(1) 110 time.Sleep(10 * time.Millisecond) 111 112 go func(i int) { 113 defer wg.Done() 114 res, err := client.Info() 115 if err != nil { 116 t.Errorf("Unexpected error: %s", err) 117 } else { 118 defer res.Body.Close() 119 } 120 }(i) 121 } 122 wg.Wait() 123 }) 124 125 t.Run("WithContext", func(t *testing.T) { 126 client, err := opensearch.NewDefaultClient() 127 if err != nil { 128 t.Fatalf("Error creating the client: %s", err) 129 } 130 131 ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond) 132 defer cancel() 133 134 res, err := client.Info(client.Info.WithContext(ctx)) 135 if err == nil { 136 res.Body.Close() 137 t.Fatal("Expected 'context deadline exceeded' error") 138 } 139 140 log.Printf("Request cancelled with %T", err) 141 }) 142 143 t.Run("Configured", func(t *testing.T) { 144 cfg := opensearch.Config{ 145 Transport: &http.Transport{ 146 MaxIdleConnsPerHost: 10, 147 ResponseHeaderTimeout: time.Second, 148 DialContext: (&net.Dialer{Timeout: time.Nanosecond}).DialContext, 149 TLSClientConfig: &tls.Config{ 150 MinVersion: tls.VersionTLS11, 151 InsecureSkipVerify: true, 152 }, 153 }, 154 } 155 156 client, err := opensearch.NewClient(cfg) 157 if err != nil { 158 t.Fatalf("Error creating the client: %s", err) 159 } 160 161 _, err = client.Info() 162 if err == nil { 163 t.Fatalf("Expected error, but got: %v", err) 164 } 165 if _, ok := err.(*net.OpError); !ok { 166 t.Fatalf("Expected net.OpError, but got: %T", err) 167 } 168 }) 169 } 170 171 type CustomTransport struct { 172 client *http.Client 173 } 174 175 func (t *CustomTransport) RoundTrip(req *http.Request) (*http.Response, error) { 176 req.Header.Set("X-Foo", "bar") 177 log.Printf("> %s %s %s\n", req.Method, req.URL.String(), req.Header) 178 return t.client.Do(req) 179 } 180 181 func TestClientCustomTransport(t *testing.T) { 182 t.Run("Customized", func(t *testing.T) { 183 cfg := opensearch.Config{ 184 Transport: &CustomTransport{ 185 client: http.DefaultClient, 186 }, 187 } 188 189 client, err := opensearch.NewClient(cfg) 190 if err != nil { 191 t.Fatalf("Error creating the client: %s", err) 192 } 193 194 for i := 0; i < 10; i++ { 195 res, err := client.Info() 196 if err != nil { 197 t.Fatalf("Unexpected error: %s", err) 198 } 199 defer res.Body.Close() 200 } 201 }) 202 203 t.Run("Manual", func(t *testing.T) { 204 tp, _ := opensearchtransport.New(opensearchtransport.Config{ 205 URLs: []*url.URL{ 206 {Scheme: "http", Host: "localhost:9200"}, 207 }, 208 Transport: http.DefaultTransport, 209 }) 210 211 client := opensearch.Client{ 212 Transport: tp, API: opensearchapi.New(tp), 213 } 214 215 for i := 0; i < 10; i++ { 216 res, err := client.Info() 217 if err != nil { 218 t.Fatalf("Unexpected error: %s", err) 219 } 220 defer res.Body.Close() 221 } 222 }) 223 } 224 225 type ReplacedTransport struct { 226 counter uint64 227 } 228 229 func (t *ReplacedTransport) Perform(req *http.Request) (*http.Response, error) { 230 req.URL.Scheme = "http" 231 req.URL.Host = "localhost:9200" 232 233 atomic.AddUint64(&t.counter, 1) 234 235 return http.DefaultTransport.RoundTrip(req) 236 } 237 238 func (t *ReplacedTransport) Count() uint64 { 239 return atomic.LoadUint64(&t.counter) 240 } 241 242 func TestClientReplaceTransport(t *testing.T) { 243 t.Run("Replaced", func(t *testing.T) { 244 tr := &ReplacedTransport{} 245 client := opensearch.Client{ 246 Transport: tr, API: opensearchapi.New(tr), 247 } 248 249 for i := 0; i < 10; i++ { 250 res, err := client.Info() 251 if err != nil { 252 t.Fatalf("Unexpected error: %s", err) 253 } 254 defer res.Body.Close() 255 } 256 257 if tr.Count() != 10 { 258 t.Errorf("Expected 10 requests, got=%d", tr.Count()) 259 } 260 }) 261 } 262 263 func TestClientAPI(t *testing.T) { 264 t.Run("Info", func(t *testing.T) { 265 client, err := opensearch.NewDefaultClient() 266 if err != nil { 267 log.Fatalf("Error creating the client: %s\n", err) 268 } 269 270 res, err := client.Info() 271 if err != nil { 272 log.Fatalf("Error getting the response: %s\n", err) 273 } 274 defer res.Body.Close() 275 276 var d map[string]interface{} 277 err = json.NewDecoder(res.Body).Decode(&d) 278 if err != nil { 279 log.Fatalf("Error parsing the response: %s\n", err) 280 } 281 }) 282 }