github.com/songzhibin97/gkit@v1.2.13/container/pool/list_test.go (about)

     1  package pool
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  type shutdown struct{}
    12  
    13  func (c *shutdown) Shutdown() error {
    14  	return nil
    15  }
    16  
    17  type connection struct {
    18  	c    IShutdown
    19  	pool Pool
    20  }
    21  
    22  func (c *connection) HandleQuick() {
    23  	// time.Sleep(1 * time.Millisecond)
    24  }
    25  
    26  func (c *connection) HandleNormal() {
    27  	time.Sleep(20 * time.Millisecond)
    28  }
    29  
    30  func (c *connection) HandleSlow() {
    31  	time.Sleep(500 * time.Millisecond)
    32  }
    33  
    34  func (c *connection) Shutdown() error {
    35  	return c.pool.Put(context.Background(), c.c, false)
    36  }
    37  
    38  func TestListGetPut(t *testing.T) {
    39  	pool := NewList(SetActive(1), SetIdle(1), SetIdleTimeout(90*time.Second), SetWait(false, 10*time.Millisecond))
    40  	pool.New(func(ctx context.Context) (IShutdown, error) {
    41  		return &shutdown{}, nil
    42  	})
    43  
    44  	// test Get Put
    45  	conn, err := pool.Get(context.TODO())
    46  	assert.Nil(t, err)
    47  	c1 := connection{pool: pool, c: conn}
    48  	c1.HandleNormal()
    49  	_ = c1.Shutdown()
    50  }
    51  
    52  func TestListPut(t *testing.T) {
    53  	id := 0
    54  	type connID struct {
    55  		IShutdown
    56  		id int
    57  	}
    58  	pool := NewList(SetActive(1), SetIdle(1), SetIdleTimeout(1*time.Second))
    59  	pool.New(func(ctx context.Context) (IShutdown, error) {
    60  		id = id + 1
    61  		return &connID{
    62  			IShutdown: &shutdown{},
    63  			id:        id,
    64  		}, nil
    65  	})
    66  
    67  	// test Put(ctx, conn, true)
    68  	conn, err := pool.Get(context.TODO())
    69  	assert.Nil(t, err)
    70  	conn1 := conn.(*connID)
    71  	// Put(ctx, conn, true) drop the connection.
    72  	_ = pool.Put(context.TODO(), conn, true)
    73  	conn, err = pool.Get(context.TODO())
    74  
    75  	assert.Nil(t, err)
    76  	conn2 := conn.(*connID)
    77  	assert.NotEqual(t, conn1.id, conn2.id)
    78  }
    79  
    80  func TestListIdleTimeout(t *testing.T) {
    81  	id := 0
    82  	type connID struct {
    83  		IShutdown
    84  		id int
    85  	}
    86  	pool := NewList(SetActive(1), SetIdle(1), SetIdleTimeout(1*time.Millisecond))
    87  	pool.New(func(ctx context.Context) (IShutdown, error) {
    88  		id = id + 1
    89  		return &connID{id: id, IShutdown: &shutdown{}}, nil
    90  	})
    91  	// test Put(ctx, conn, true)
    92  	conn, err := pool.Get(context.TODO())
    93  
    94  	assert.Nil(t, err)
    95  	conn1 := conn.(*connID)
    96  	// Put(ctx, conn, true) drop the connection.
    97  	_ = pool.Put(context.TODO(), conn, false)
    98  	time.Sleep(5 * time.Millisecond)
    99  	// idletimeout and get new conn
   100  	conn, err = pool.Get(context.TODO())
   101  
   102  	assert.Nil(t, err)
   103  	conn2 := conn.(*connID)
   104  
   105  	assert.NotEqual(t, conn1.id, conn2.id)
   106  }
   107  
   108  func TestListContextTimeout(t *testing.T) {
   109  	// new pool
   110  	pool := NewList(SetActive(1), SetIdle(1), SetIdleTimeout(90*time.Second), SetWait(false, 10*time.Millisecond))
   111  	pool.New(func(ctx context.Context) (IShutdown, error) {
   112  		return &shutdown{}, nil
   113  	})
   114  	// test context timeout
   115  	ctx, cancel := context.WithTimeout(context.TODO(), 100*time.Millisecond)
   116  	defer cancel()
   117  	conn, err := pool.Get(ctx)
   118  
   119  	assert.Nil(t, err)
   120  	_, err = pool.Get(ctx)
   121  	// context timeout error
   122  	assert.NotNil(t, err)
   123  	_ = pool.Put(context.TODO(), conn, false)
   124  	_, err = pool.Get(ctx)
   125  	assert.Nil(t, err)
   126  }
   127  
   128  func TestListPoolExhausted(t *testing.T) {
   129  	// test pool exhausted
   130  
   131  	pool := NewList(SetActive(1), SetIdle(1), SetIdleTimeout(90*time.Second))
   132  	pool.New(func(ctx context.Context) (IShutdown, error) {
   133  		return &shutdown{}, nil
   134  	})
   135  
   136  	ctx, cancel := context.WithTimeout(context.TODO(), 100*time.Millisecond)
   137  	defer cancel()
   138  	conn, err := pool.Get(context.TODO())
   139  	assert.Nil(t, err)
   140  	_, err = pool.Get(ctx)
   141  	// config active == 1, so no available conns make connection exhausted.
   142  	assert.NotNil(t, err)
   143  	_ = pool.Put(context.TODO(), conn, false)
   144  	_, err = pool.Get(ctx)
   145  	assert.Nil(t, err)
   146  }
   147  
   148  func TestListStaleClean(t *testing.T) {
   149  	id := 0
   150  	type connID struct {
   151  		IShutdown
   152  		id int
   153  	}
   154  	pool := NewList(SetActive(1), SetIdle(1), SetIdleTimeout(1*time.Second))
   155  	pool.New(func(ctx context.Context) (IShutdown, error) {
   156  		id = id + 1
   157  		return &connID{id: id, IShutdown: &shutdown{}}, nil
   158  	})
   159  	conn, err := pool.Get(context.TODO())
   160  	assert.Nil(t, err)
   161  	conn1 := conn.(*connID)
   162  	_ = pool.Put(context.TODO(), conn, false)
   163  	conn, err = pool.Get(context.TODO())
   164  	assert.Nil(t, err)
   165  	conn2 := conn.(*connID)
   166  	assert.Equal(t, conn1.id, conn2.id)
   167  	_ = pool.Put(context.TODO(), conn, false)
   168  	// sleep more than idleTimeout
   169  	time.Sleep(2 * time.Second)
   170  	conn, err = pool.Get(context.TODO())
   171  	assert.Nil(t, err)
   172  	conn3 := conn.(*connID)
   173  	assert.NotEqual(t, conn1.id, conn3.id)
   174  }
   175  
   176  func BenchmarkList(b *testing.B) {
   177  	pool := NewList(SetActive(30), SetIdle(30), SetIdleTimeout(90*time.Second), SetWait(false, 10*time.Millisecond))
   178  	pool.New(func(ctx context.Context) (IShutdown, error) {
   179  		return &shutdown{}, nil
   180  	})
   181  	for i := 0; i < b.N; i++ {
   182  		conn, err := pool.Get(context.TODO())
   183  		if err != nil {
   184  			b.Error(err)
   185  			continue
   186  		}
   187  		c1 := connection{pool: pool, c: conn}
   188  		c1.HandleQuick()
   189  		_ = pool.Put(context.TODO(), conn, false)
   190  	}
   191  }
   192  
   193  func BenchmarkList1(b *testing.B) {
   194  	pool := NewList(SetActive(30), SetIdle(30), SetIdleTimeout(90*time.Second), SetWait(false, 10*time.Millisecond))
   195  	pool.New(func(ctx context.Context) (IShutdown, error) {
   196  		return &shutdown{}, nil
   197  	})
   198  
   199  	b.ResetTimer()
   200  	b.RunParallel(func(pb *testing.PB) {
   201  		for pb.Next() {
   202  			conn, err := pool.Get(context.TODO())
   203  			if err != nil {
   204  				b.Error(err)
   205  				continue
   206  			}
   207  			c1 := connection{pool: pool, c: conn}
   208  			c1.HandleQuick()
   209  			_ = c1.Shutdown()
   210  		}
   211  	})
   212  }
   213  
   214  func BenchmarkList2(b *testing.B) {
   215  	pool := NewList(SetActive(30), SetIdle(30), SetIdleTimeout(90*time.Second), SetWait(false, 10*time.Millisecond))
   216  	pool.New(func(ctx context.Context) (IShutdown, error) {
   217  		return &shutdown{}, nil
   218  	})
   219  
   220  	b.ResetTimer()
   221  	b.RunParallel(func(pb *testing.PB) {
   222  		for pb.Next() {
   223  			conn, err := pool.Get(context.TODO())
   224  			if err != nil {
   225  				b.Error(err)
   226  				continue
   227  			}
   228  			c1 := connection{pool: pool, c: conn}
   229  			c1.HandleNormal()
   230  			_ = c1.Shutdown()
   231  		}
   232  	})
   233  }
   234  
   235  func BenchmarkPool3(b *testing.B) {
   236  	pool := NewList(SetActive(30), SetIdle(30), SetIdleTimeout(90*time.Second), SetWait(false, 10*time.Millisecond))
   237  	pool.New(func(ctx context.Context) (IShutdown, error) {
   238  		return &shutdown{}, nil
   239  	})
   240  
   241  	b.ResetTimer()
   242  	b.RunParallel(func(pb *testing.PB) {
   243  		for pb.Next() {
   244  			conn, err := pool.Get(context.TODO())
   245  			if err != nil {
   246  				b.Error(err)
   247  				continue
   248  			}
   249  			c1 := connection{pool: pool, c: conn}
   250  			c1.HandleSlow()
   251  			_ = c1.Shutdown()
   252  		}
   253  	})
   254  }
   255  
   256  func BenchmarkList4(b *testing.B) {
   257  	pool := NewList(SetActive(30), SetIdle(30), SetIdleTimeout(90*time.Second))
   258  	pool.New(func(ctx context.Context) (IShutdown, error) {
   259  		return &shutdown{}, nil
   260  	})
   261  
   262  	b.ResetTimer()
   263  	b.RunParallel(func(pb *testing.PB) {
   264  		for pb.Next() {
   265  			conn, err := pool.Get(context.TODO())
   266  			if err != nil {
   267  				b.Error(err)
   268  				continue
   269  			}
   270  			c1 := connection{pool: pool, c: conn}
   271  			c1.HandleSlow()
   272  			_ = c1.Shutdown()
   273  		}
   274  	})
   275  }
   276  
   277  func BenchmarkList5(b *testing.B) {
   278  	pool := NewList(SetActive(30), SetIdle(30), SetIdleTimeout(90*time.Second))
   279  	pool.New(func(ctx context.Context) (IShutdown, error) {
   280  		return &shutdown{}, nil
   281  	})
   282  
   283  	b.ResetTimer()
   284  	b.RunParallel(func(pb *testing.PB) {
   285  		for pb.Next() {
   286  			conn, err := pool.Get(context.TODO())
   287  			if err != nil {
   288  				b.Error(err)
   289  				continue
   290  			}
   291  			c1 := connection{pool: pool, c: conn}
   292  			c1.HandleSlow()
   293  			_ = c1.Shutdown()
   294  		}
   295  	})
   296  }