github.com/hashicorp/vault/sdk@v0.11.0/helper/clientcountutil/clientcountutil_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package clientcountutil 5 6 import ( 7 "context" 8 "encoding/json" 9 "io" 10 "net/http" 11 "net/http/httptest" 12 "testing" 13 14 "github.com/hashicorp/vault/api" 15 "github.com/hashicorp/vault/sdk/helper/clientcountutil/generation" 16 "github.com/stretchr/testify/require" 17 ) 18 19 // TestNewCurrentMonthData verifies that current month is set correctly and that 20 // there are no open segments 21 func TestNewCurrentMonthData(t *testing.T) { 22 generator := NewActivityLogData(nil).NewCurrentMonthData() 23 require.True(t, generator.data.Data[0].GetCurrentMonth()) 24 require.True(t, generator.addingToMonth.GetCurrentMonth()) 25 require.Nil(t, generator.addingToSegment) 26 } 27 28 // TestNewMonthDataMonthsAgo verifies that months ago is set correctly and that 29 // there are no open segments 30 func TestNewMonthDataMonthsAgo(t *testing.T) { 31 generator := NewActivityLogData(nil).NewPreviousMonthData(3) 32 require.Equal(t, int32(3), generator.data.Data[0].GetMonthsAgo()) 33 require.Equal(t, int32(3), generator.addingToMonth.GetMonthsAgo()) 34 require.Nil(t, generator.addingToSegment) 35 } 36 37 // TestNewMonthData_MultipleMonths opens a month 3 months ago then 2 months ago. 38 // The test verifies that the generator is set to add to the correct month. We 39 // then open a current month, and verify that the generator will add to the 40 // current month. 41 func TestNewMonthData_MultipleMonths(t *testing.T) { 42 generator := NewActivityLogData(nil).NewPreviousMonthData(3).NewPreviousMonthData(2) 43 require.Equal(t, int32(2), generator.data.Data[1].GetMonthsAgo()) 44 require.Equal(t, int32(2), generator.addingToMonth.GetMonthsAgo()) 45 generator = generator.NewCurrentMonthData() 46 require.True(t, generator.data.Data[2].GetCurrentMonth()) 47 require.True(t, generator.addingToMonth.GetCurrentMonth()) 48 } 49 50 // TestNewCurrentMonthData_ClientsSeen calls ClientsSeen with 3 clients, and 51 // verifies that they are added to the input data 52 func TestNewCurrentMonthData_ClientsSeen(t *testing.T) { 53 wantClients := []*generation.Client{ 54 { 55 Id: "1", 56 Namespace: "ns", 57 Mount: "mount", 58 ClientType: "non-entity", 59 }, 60 { 61 Id: "2", 62 }, 63 { 64 Id: "3", 65 Count: int32(3), 66 }, 67 } 68 generator := NewActivityLogData(nil).NewCurrentMonthData().ClientsSeen(wantClients...) 69 require.Equal(t, generator.data.Data[0].GetAll().Clients, wantClients) 70 require.True(t, generator.data.Data[0].GetCurrentMonth()) 71 } 72 73 // TestSegment_AddClients adds clients in a variety of ways to an open segment 74 // and verifies that the clients are present in the segment with the correct 75 // options 76 func TestSegment_AddClients(t *testing.T) { 77 testAddClients(t, func() *ActivityLogDataGenerator { 78 return NewActivityLogData(nil).NewCurrentMonthData().Segment() 79 }, func(g *ActivityLogDataGenerator) *generation.Client { 80 return g.data.Data[0].GetSegments().Segments[0].Clients.Clients[0] 81 }) 82 } 83 84 // TestSegment_MultipleSegments opens a current month and adds a client to an 85 // un-indexed segment, then opens an indexed segment and adds a client. The test 86 // verifies that clients are present in both segments, and that the segment 87 // index is correctly recorded 88 func TestSegment_MultipleSegments(t *testing.T) { 89 generator := NewActivityLogData(nil).NewCurrentMonthData().Segment().NewClientSeen().Segment(WithSegmentIndex(2)).NewClientSeen() 90 require.Len(t, generator.data.Data[0].GetSegments().Segments[0].Clients.Clients, 1) 91 require.Len(t, generator.data.Data[0].GetSegments().Segments[1].Clients.Clients, 1) 92 require.Equal(t, int32(2), *generator.data.Data[0].GetSegments().Segments[1].SegmentIndex) 93 require.Equal(t, int32(2), *generator.addingToSegment.SegmentIndex) 94 } 95 96 // TestSegment_NewMonth adds a client to a segment, then starts a new month. The 97 // test verifies that there are no open segments 98 func TestSegment_NewMonth(t *testing.T) { 99 generator := NewActivityLogData(nil).NewCurrentMonthData().Segment().NewClientSeen().NewPreviousMonthData(1) 100 require.Nil(t, generator.addingToSegment) 101 } 102 103 // TestNewCurrentMonthData_AddClients adds clients in a variety of ways to an 104 // the current month and verifies that the clients are present in the month with 105 // the correct options 106 func TestNewCurrentMonthData_AddClients(t *testing.T) { 107 testAddClients(t, func() *ActivityLogDataGenerator { 108 return NewActivityLogData(nil).NewCurrentMonthData() 109 }, func(g *ActivityLogDataGenerator) *generation.Client { 110 return g.data.Data[0].GetAll().Clients[0] 111 }) 112 } 113 114 // TestWrite creates a mock http server and writes generated data to it. The 115 // test verifies that the returned paths are parsed correctly, and that the JSON 116 // sent to the server is correct. 117 func TestWrite(t *testing.T) { 118 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 119 _, err := io.WriteString(w, `{"data":{"paths":["path1","path2"]}}`) 120 require.NoError(t, err) 121 body, err := io.ReadAll(r.Body) 122 require.NoError(t, err) 123 raw := map[string]string{} 124 err = json.Unmarshal(body, &raw) 125 require.NoError(t, err) 126 require.JSONEq(t, `{"write":["WRITE_ENTITIES"],"data":[{"monthsAgo":3,"all":{"clients":[{"count":1}]}},{"monthsAgo":2,"segments":{"segments":[{"segmentIndex":2,"clients":{"clients":[{"count":1,"repeated":true}]}}]}},{"currentMonth":true}]}`, raw["input"]) 127 })) 128 defer ts.Close() 129 130 client, err := api.NewClient(&api.Config{ 131 Address: ts.URL, 132 }) 133 require.NoError(t, err) 134 paths, err := NewActivityLogData(client). 135 NewPreviousMonthData(3). 136 NewClientSeen(). 137 NewPreviousMonthData(2). 138 Segment(WithSegmentIndex(2)). 139 RepeatedClientSeen(). 140 NewCurrentMonthData().Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES) 141 142 require.NoError(t, err) 143 require.Equal(t, []string{"path1", "path2"}, paths) 144 } 145 146 func testAddClients(t *testing.T, makeGenerator func() *ActivityLogDataGenerator, getClient func(data *ActivityLogDataGenerator) *generation.Client) { 147 t.Helper() 148 clientOptions := []ClientOption{ 149 WithClientNamespace("ns"), WithClientMount("mount"), WithClientIsNonEntity(), WithClientID("1"), 150 } 151 generator := makeGenerator().NewClientSeen(clientOptions...) 152 require.Equal(t, getClient(generator), &generation.Client{ 153 Id: "1", 154 Count: 1, 155 Namespace: "ns", 156 Mount: "mount", 157 ClientType: "non-entity", 158 }) 159 160 generator = makeGenerator().NewClientsSeen(4, clientOptions...) 161 require.Equal(t, getClient(generator), &generation.Client{ 162 Id: "1", 163 Count: 4, 164 Namespace: "ns", 165 Mount: "mount", 166 ClientType: "non-entity", 167 }) 168 169 generator = makeGenerator().RepeatedClientSeen(clientOptions...) 170 require.Equal(t, getClient(generator), &generation.Client{ 171 Id: "1", 172 Count: 1, 173 Repeated: true, 174 Namespace: "ns", 175 Mount: "mount", 176 ClientType: "non-entity", 177 }) 178 179 generator = makeGenerator().RepeatedClientsSeen(4, clientOptions...) 180 require.Equal(t, getClient(generator), &generation.Client{ 181 Id: "1", 182 Count: 4, 183 Repeated: true, 184 Namespace: "ns", 185 Mount: "mount", 186 ClientType: "non-entity", 187 }) 188 189 generator = makeGenerator().RepeatedClientSeenFromMonthsAgo(3, clientOptions...) 190 require.Equal(t, getClient(generator), &generation.Client{ 191 Id: "1", 192 Count: 1, 193 RepeatedFromMonth: 3, 194 Namespace: "ns", 195 Mount: "mount", 196 ClientType: "non-entity", 197 }) 198 199 generator = makeGenerator().RepeatedClientsSeenFromMonthsAgo(4, 3, clientOptions...) 200 require.Equal(t, getClient(generator), &generation.Client{ 201 Id: "1", 202 Count: 4, 203 RepeatedFromMonth: 3, 204 Namespace: "ns", 205 Mount: "mount", 206 ClientType: "non-entity", 207 }) 208 } 209 210 // TestSetMonthOptions sets month options and verifies that they are saved 211 func TestSetMonthOptions(t *testing.T) { 212 generator := NewActivityLogData(nil).NewCurrentMonthData().SetMonthOptions(WithEmptySegmentIndexes(3, 4), 213 WithMaximumSegmentIndex(7), WithSkipSegmentIndexes(1, 2)) 214 require.Equal(t, int32(7), generator.data.Data[0].NumSegments) 215 require.Equal(t, []int32{3, 4}, generator.data.Data[0].EmptySegmentIndexes) 216 require.Equal(t, []int32{1, 2}, generator.data.Data[0].SkipSegmentIndexes) 217 } 218 219 // TestVerifyInput constructs invalid inputs and ensures that VerifyInput 220 // returns an error 221 func TestVerifyInput(t *testing.T) { 222 cases := []struct { 223 name string 224 generator *ActivityLogDataGenerator 225 }{ 226 { 227 name: "repeated client with only 1 month", 228 generator: NewActivityLogData(nil). 229 NewCurrentMonthData(). 230 RepeatedClientSeen(), 231 }, 232 { 233 name: "repeated client with segment", 234 generator: NewActivityLogData(nil). 235 NewCurrentMonthData(). 236 Segment(). 237 RepeatedClientSeen(), 238 }, 239 { 240 name: "repeated client with earliest month", 241 generator: NewActivityLogData(nil). 242 NewCurrentMonthData(). 243 NewClientSeen(). 244 NewPreviousMonthData(2). 245 RepeatedClientSeen(), 246 }, 247 { 248 name: "repeated month", 249 generator: NewActivityLogData(nil). 250 NewPreviousMonthData(1). 251 NewPreviousMonthData(1), 252 }, 253 { 254 name: "repeated current month", 255 generator: NewActivityLogData(nil). 256 NewCurrentMonthData(). 257 NewCurrentMonthData(), 258 }, 259 { 260 name: "repeated segment index", 261 generator: NewActivityLogData(nil). 262 NewCurrentMonthData(). 263 Segment(WithSegmentIndex(1)). 264 Segment(WithSegmentIndex(1)), 265 }, 266 { 267 name: "segment with num segments", 268 generator: NewActivityLogData(nil). 269 NewCurrentMonthData(). 270 Segment(). 271 SetMonthOptions(WithMaximumSegmentIndex(1)), 272 }, 273 } 274 for _, tc := range cases { 275 t.Run(tc.name, func(t *testing.T) { 276 require.Error(t, VerifyInput(tc.generator.data)) 277 }) 278 } 279 }