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 }