github.com/opensearch-project/opensearch-go/v2@v2.3.0/opensearchtransport/connection_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
    28  
    29  package opensearchtransport
    30  
    31  import (
    32  	"fmt"
    33  	"net/http"
    34  	"net/url"
    35  	"os"
    36  	"testing"
    37  	"time"
    38  )
    39  
    40  func NewServer(addr string, handler http.Handler) *http.Server {
    41  	return &http.Server{Addr: addr, Handler: handler}
    42  }
    43  
    44  func TestStatusConnectionPool(t *testing.T) {
    45  	defaultResurrectTimeoutInitial = time.Second
    46  	defer func() { defaultResurrectTimeoutInitial = 60 * time.Second }()
    47  
    48  	var (
    49  		server      *http.Server
    50  		servers     []*http.Server
    51  		serverURLs  []*url.URL
    52  		serverHosts []string
    53  		numServers  = 3
    54  
    55  		defaultHandler = func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "OK") }
    56  	)
    57  
    58  	for i := 1; i <= numServers; i++ {
    59  		s := NewServer(fmt.Sprintf("localhost:1000%d", i), http.HandlerFunc(defaultHandler))
    60  
    61  		go func(s *http.Server) {
    62  			if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
    63  				t.Fatalf("Unable to start server: %s", err)
    64  			}
    65  		}(s)
    66  
    67  		defer func(s *http.Server) { s.Close() }(s)
    68  
    69  		servers = append(servers, s)
    70  		time.Sleep(time.Millisecond)
    71  	}
    72  
    73  	for _, s := range servers {
    74  		u, _ := url.Parse("http://" + s.Addr)
    75  		serverURLs = append(serverURLs, u)
    76  		serverHosts = append(serverHosts, u.String())
    77  	}
    78  
    79  	fmt.Printf("==> Started %d servers on %s\n", numServers, serverHosts)
    80  
    81  	cfg := Config{URLs: serverURLs}
    82  
    83  	if _, ok := os.LookupEnv("GITHUB_ACTIONS"); !ok {
    84  		cfg.Logger = &TextLogger{Output: os.Stdout}
    85  		cfg.EnableDebugLogger = true
    86  	}
    87  
    88  	transport, _ := New(cfg)
    89  
    90  	pool := transport.pool.(*statusConnectionPool)
    91  
    92  	for i := 1; i <= 9; i++ {
    93  		req, _ := http.NewRequest("GET", "/", nil)
    94  		res, err := transport.Perform(req)
    95  		if err != nil {
    96  			t.Errorf("Unexpected error: %v", err)
    97  		}
    98  		if res.StatusCode != 200 {
    99  			t.Errorf("Unexpected status code, want=200, got=%d", res.StatusCode)
   100  		}
   101  	}
   102  
   103  	pool.Lock()
   104  	if len(pool.live) != 3 {
   105  		t.Errorf("Unexpected number of live connections, want=3, got=%d", len(pool.live))
   106  	}
   107  	pool.Unlock()
   108  
   109  	server = servers[1]
   110  	fmt.Printf("==> Closing server: %s\n", server.Addr)
   111  	if err := server.Close(); err != nil {
   112  		t.Fatalf("Unable to close server: %s", err)
   113  	}
   114  
   115  	for i := 1; i <= 9; i++ {
   116  		req, _ := http.NewRequest("GET", "/", nil)
   117  		res, err := transport.Perform(req)
   118  		if err != nil {
   119  			t.Errorf("Unexpected error: %v", err)
   120  		}
   121  		if res.StatusCode != 200 {
   122  			t.Errorf("Unexpected status code, want=200, got=%d", res.StatusCode)
   123  		}
   124  	}
   125  
   126  	pool.Lock()
   127  	if len(pool.live) != 2 {
   128  		t.Errorf("Unexpected number of live connections, want=2, got=%d", len(pool.live))
   129  	}
   130  	pool.Unlock()
   131  
   132  	pool.Lock()
   133  	if len(pool.dead) != 1 {
   134  		t.Errorf("Unexpected number of dead connections, want=1, got=%d", len(pool.dead))
   135  	}
   136  	pool.Unlock()
   137  
   138  	server = NewServer("localhost:10002", http.HandlerFunc(defaultHandler))
   139  	servers[1] = server
   140  	fmt.Printf("==> Starting server: %s\n", server.Addr)
   141  	go func() {
   142  		if err := server.ListenAndServe(); err != nil {
   143  			t.Fatalf("Unable to start server: %s", err)
   144  		}
   145  	}()
   146  
   147  	fmt.Println("==> Waiting 1.25s for resurrection...")
   148  	time.Sleep(1250 * time.Millisecond)
   149  
   150  	for i := 1; i <= 9; i++ {
   151  		req, _ := http.NewRequest("GET", "/", nil)
   152  		res, err := transport.Perform(req)
   153  		if err != nil {
   154  			t.Errorf("Unexpected error: %v", err)
   155  		}
   156  		if res.StatusCode != 200 {
   157  			t.Errorf("Unexpected status code, want=200, got=%d", res.StatusCode)
   158  		}
   159  	}
   160  
   161  	pool.Lock()
   162  	if len(pool.live) != 3 {
   163  		t.Errorf("Unexpected number of live connections, want=3, got=%d", len(pool.live))
   164  	}
   165  	pool.Unlock()
   166  
   167  	pool.Lock()
   168  	if len(pool.dead) != 0 {
   169  		t.Errorf("Unexpected number of dead connections, want=0, got=%d", len(pool.dead))
   170  	}
   171  	pool.Unlock()
   172  }