github.com/hernad/nomad@v1.6.112/helper/users/cache_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  //go:build unix
     5  
     6  package users
     7  
     8  import (
     9  	"errors"
    10  	"os/user"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/hernad/nomad/ci"
    15  	"github.com/shoenig/test/must"
    16  	"oss.indeed.com/go/libtime/libtimetest"
    17  )
    18  
    19  func TestCache_real_hit(t *testing.T) {
    20  	ci.Parallel(t)
    21  
    22  	c := newCache()
    23  
    24  	// fresh lookup
    25  	u, err := c.GetUser("nobody")
    26  	must.NoError(t, err)
    27  	must.NotNil(t, u)
    28  
    29  	// hit again, cached value
    30  	u2, err2 := c.GetUser("nobody")
    31  	must.NoError(t, err2)
    32  	must.NotNil(t, u2)
    33  	must.True(t, u == u2) // compare pointers
    34  }
    35  
    36  func TestCache_real_miss(t *testing.T) {
    37  	ci.Parallel(t)
    38  
    39  	c := newCache()
    40  
    41  	// fresh lookup
    42  	u, err := c.GetUser("doesnotexist")
    43  	must.Error(t, err)
    44  	must.Nil(t, u)
    45  
    46  	// hit again, cached value
    47  	u2, err2 := c.GetUser("doesnotexist")
    48  	must.Error(t, err2)
    49  	must.Nil(t, u2)
    50  	must.True(t, err == err2) // compare pointers
    51  }
    52  
    53  func TestCache_mock_hit(t *testing.T) {
    54  	ci.Parallel(t)
    55  
    56  	c := newCache()
    57  
    58  	lookupCount := 0
    59  
    60  	// hijack the underlying lookup function with our own mock
    61  	c.lookupUser = func(username string) (*user.User, error) {
    62  		lookupCount++
    63  		return &user.User{Name: username}, nil
    64  	}
    65  
    66  	// hijack the clock with our own mock
    67  	t0 := time.Now()
    68  	clockCount := 0
    69  	c.clock = libtimetest.NewClockMock(t).NowMock.Set(func() time.Time {
    70  		clockCount++
    71  		switch clockCount {
    72  		case 1:
    73  			return t0
    74  		case 2:
    75  			return t0.Add(59 * time.Minute)
    76  		default:
    77  			return t0.Add(61 * time.Minute)
    78  		}
    79  	})
    80  
    81  	const username = "armon"
    82  
    83  	// initial lookup
    84  	u, err := c.GetUser(username)
    85  	must.NoError(t, err)
    86  	must.Eq(t, "armon", u.Name)
    87  	must.Eq(t, 1, lookupCount)
    88  	must.Eq(t, 1, clockCount)
    89  
    90  	// second lookup, 59 minutes after initil lookup
    91  	u2, err2 := c.GetUser(username)
    92  	must.NoError(t, err2)
    93  	must.Eq(t, "armon", u2.Name)
    94  	must.Eq(t, 1, lookupCount) // was in cache
    95  	must.Eq(t, 2, clockCount)
    96  
    97  	// third lookup, 61 minutes after initial lookup (expired)
    98  	u3, err3 := c.GetUser(username)
    99  	must.NoError(t, err3)
   100  	must.Eq(t, "armon", u3.Name)
   101  	must.Eq(t, 2, lookupCount)
   102  	must.Eq(t, 3, clockCount)
   103  }
   104  
   105  func TestCache_mock_miss(t *testing.T) {
   106  	ci.Parallel(t)
   107  
   108  	c := newCache()
   109  
   110  	lookupCount := 0
   111  	lookupErr := errors.New("lookup error")
   112  
   113  	// hijack the underlying lookup function with our own mock
   114  	c.lookupUser = func(username string) (*user.User, error) {
   115  		lookupCount++
   116  		return nil, lookupErr
   117  	}
   118  
   119  	// hijack the clock with our own mock
   120  	t0 := time.Now()
   121  	clockCount := 0
   122  	c.clock = libtimetest.NewClockMock(t).NowMock.Set(func() time.Time {
   123  		clockCount++
   124  		switch clockCount {
   125  		case 1:
   126  			return t0
   127  		case 2:
   128  			return t0.Add(59 * time.Second)
   129  		default:
   130  			return t0.Add(61 * time.Second)
   131  		}
   132  	})
   133  
   134  	const username = "armon"
   135  
   136  	// initial lookup
   137  	u, err := c.GetUser(username)
   138  	must.ErrorIs(t, err, lookupErr)
   139  	must.Nil(t, u)
   140  	must.Eq(t, 1, lookupCount)
   141  	must.Eq(t, 1, clockCount)
   142  
   143  	// second lookup, 59 seconds after initial (still in cache)
   144  	u2, err2 := c.GetUser(username)
   145  	must.ErrorIs(t, err2, lookupErr)
   146  	must.Nil(t, u2)
   147  	must.Eq(t, 1, lookupCount) // in cache
   148  	must.Eq(t, 2, clockCount)
   149  
   150  	// third lookup, 61 seconds after initial (expired)
   151  	u3, err3 := c.GetUser(username)
   152  	must.ErrorIs(t, err3, lookupErr)
   153  	must.Nil(t, u3)
   154  	must.Eq(t, 2, lookupCount)
   155  	must.Eq(t, 3, clockCount)
   156  }