github.com/hernad/nomad@v1.6.112/nomad/state/state_store_acl_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package state 5 6 import ( 7 "fmt" 8 "testing" 9 "time" 10 11 "github.com/hashicorp/go-memdb" 12 "github.com/hernad/nomad/ci" 13 "github.com/hernad/nomad/helper/pointer" 14 "github.com/hernad/nomad/helper/uuid" 15 "github.com/hernad/nomad/nomad/mock" 16 "github.com/hernad/nomad/nomad/structs" 17 "github.com/shoenig/test/must" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestStateStore_ACLTokensByExpired(t *testing.T) { 22 ci.Parallel(t) 23 testState := testStateStore(t) 24 25 // This function provides an easy way to get all tokens out of the 26 // iterator. 27 fromIteratorFunc := func(iter memdb.ResultIterator) []*structs.ACLToken { 28 var tokens []*structs.ACLToken 29 for raw := iter.Next(); raw != nil; raw = iter.Next() { 30 tokens = append(tokens, raw.(*structs.ACLToken)) 31 } 32 return tokens 33 } 34 35 // This time is the threshold for all expiry calls to be based on. All 36 // tokens with expiry can use this as their base and use Add(). 37 expiryTimeThreshold := time.Date(2022, time.April, 27, 14, 50, 0, 0, time.UTC) 38 39 // Generate two tokens without an expiry time. These tokens should never 40 // show up in calls to ACLTokensByExpired. 41 neverExpireLocalToken := mock.ACLToken() 42 neverExpireGlobalToken := mock.ACLToken() 43 neverExpireLocalToken.Global = true 44 45 // Upsert the tokens into state and perform a global and local read of 46 // the state. 47 err := testState.UpsertACLTokens(structs.MsgTypeTestSetup, 10, []*structs.ACLToken{ 48 neverExpireLocalToken, neverExpireGlobalToken}) 49 require.NoError(t, err) 50 51 iter, err := testState.ACLTokensByExpired(true) 52 require.NoError(t, err) 53 tokens := fromIteratorFunc(iter) 54 require.Len(t, tokens, 0) 55 56 iter, err = testState.ACLTokensByExpired(false) 57 require.NoError(t, err) 58 tokens = fromIteratorFunc(iter) 59 require.Len(t, tokens, 0) 60 61 // Generate, upsert, and test an expired local token. This token expired 62 // long ago and therefore before all others coming in the tests. It should 63 // therefore always be the first out. 64 expiredLocalToken := mock.ACLToken() 65 expiredLocalToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(-48 * time.Hour)) 66 67 err = testState.UpsertACLTokens(structs.MsgTypeTestSetup, 20, []*structs.ACLToken{expiredLocalToken}) 68 require.NoError(t, err) 69 70 iter, err = testState.ACLTokensByExpired(false) 71 require.NoError(t, err) 72 tokens = fromIteratorFunc(iter) 73 require.Len(t, tokens, 1) 74 require.Equal(t, expiredLocalToken.AccessorID, tokens[0].AccessorID) 75 76 // Generate, upsert, and test an expired global token. This token expired 77 // long ago and therefore before all others coming in the tests. It should 78 // therefore always be the first out. 79 expiredGlobalToken := mock.ACLToken() 80 expiredGlobalToken.Global = true 81 expiredGlobalToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(-48 * time.Hour)) 82 83 err = testState.UpsertACLTokens(structs.MsgTypeTestSetup, 30, []*structs.ACLToken{expiredGlobalToken}) 84 require.NoError(t, err) 85 86 iter, err = testState.ACLTokensByExpired(true) 87 require.NoError(t, err) 88 tokens = fromIteratorFunc(iter) 89 require.Len(t, tokens, 1) 90 require.Equal(t, expiredGlobalToken.AccessorID, tokens[0].AccessorID) 91 92 // This test function allows us to run the same test for local and global 93 // tokens. 94 testFn := func(oldToken *structs.ACLToken, global bool) { 95 96 // Track all the expected expired ACL tokens, including the long 97 // expired token. 98 var expiredTokens []*structs.ACLToken 99 expiredTokens = append(expiredTokens, oldToken) 100 101 // Generate and upsert a number of mixed expired, non-expired tokens. 102 mixedTokens := make([]*structs.ACLToken, 20) 103 for i := 0; i < 20; i++ { 104 mockedToken := mock.ACLToken() 105 mockedToken.Global = global 106 if i%2 == 0 { 107 expiredTokens = append(expiredTokens, mockedToken) 108 mockedToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(-24 * time.Hour)) 109 } else { 110 mockedToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(24 * time.Hour)) 111 } 112 mixedTokens[i] = mockedToken 113 } 114 115 err = testState.UpsertACLTokens(structs.MsgTypeTestSetup, 40, mixedTokens) 116 require.NoError(t, err) 117 118 // Check the full listing works as expected as the first 11 elements 119 // should all be our expired tokens. Ensure our oldest expired token is 120 // first in the list. 121 iter, err = testState.ACLTokensByExpired(global) 122 require.NoError(t, err) 123 tokens = fromIteratorFunc(iter) 124 require.ElementsMatch(t, expiredTokens, tokens[:11]) 125 require.Equal(t, tokens[0], oldToken) 126 } 127 128 testFn(expiredLocalToken, false) 129 testFn(expiredGlobalToken, true) 130 } 131 132 func Test_expiresIndexName(t *testing.T) { 133 testCases := []struct { 134 globalInput bool 135 expectedOutput string 136 name string 137 }{ 138 { 139 globalInput: false, 140 expectedOutput: indexExpiresLocal, 141 name: "local", 142 }, 143 { 144 globalInput: true, 145 expectedOutput: indexExpiresGlobal, 146 name: "global", 147 }, 148 } 149 150 for _, tc := range testCases { 151 t.Run(tc.name, func(t *testing.T) { 152 actualOutput := expiresIndexName(tc.globalInput) 153 require.Equal(t, tc.expectedOutput, actualOutput) 154 }) 155 } 156 } 157 158 func TestStateStore_UpsertACLRoles(t *testing.T) { 159 ci.Parallel(t) 160 testState := testStateStore(t) 161 162 // Generate a mocked ACL role for testing and attempt to upsert this 163 // straight into state. It should fail because the ACL policies do not 164 // exist. 165 mockedACLRoles := []*structs.ACLRole{mock.ACLRole()} 166 err := testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false) 167 require.ErrorContains(t, err, "policy not found") 168 169 // Create the policies our ACL roles wants to link to and then try the 170 // upsert again. 171 policy1 := mock.ACLPolicy() 172 policy1.Name = "mocked-test-policy-1" 173 policy2 := mock.ACLPolicy() 174 policy2.Name = "mocked-test-policy-2" 175 176 require.NoError(t, testState.UpsertACLPolicies( 177 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 178 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 20, mockedACLRoles, false)) 179 180 // Check that the index for the table was modified as expected. 181 initialIndex, err := testState.Index(TableACLRoles) 182 require.NoError(t, err) 183 must.Eq(t, 20, initialIndex) 184 185 // List all the ACL roles in the table, so we can perform a number of tests 186 // on the return array. 187 ws := memdb.NewWatchSet() 188 iter, err := testState.GetACLRoles(ws) 189 require.NoError(t, err) 190 191 // Count how many table entries we have, to ensure it is the expected 192 // number. 193 var count int 194 195 for raw := iter.Next(); raw != nil; raw = iter.Next() { 196 count++ 197 198 // Ensure the create and modify indexes are populated correctly. 199 aclRole := raw.(*structs.ACLRole) 200 must.Eq(t, 20, aclRole.CreateIndex) 201 must.Eq(t, 20, aclRole.ModifyIndex) 202 } 203 require.Equal(t, 1, count, "incorrect number of ACL roles found") 204 205 // Try writing the same ACL roles to state which should not result in an 206 // update to the table index. 207 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 30, mockedACLRoles, false)) 208 reInsertActualIndex, err := testState.Index(TableACLRoles) 209 require.NoError(t, err) 210 must.Eq(t, 20, reInsertActualIndex) 211 212 // Make a change to one of the ACL roles and ensure this update is accepted 213 // and the table index is updated. 214 updatedMockedACLRole := mockedACLRoles[0].Copy() 215 updatedMockedACLRole.Policies = []*structs.ACLRolePolicyLink{{Name: "mocked-test-policy-1"}} 216 updatedMockedACLRole.SetHash() 217 require.NoError(t, testState.UpsertACLRoles( 218 structs.MsgTypeTestSetup, 30, []*structs.ACLRole{updatedMockedACLRole}, false)) 219 220 // Check that the index for the table was modified as expected. 221 updatedIndex, err := testState.Index(TableACLRoles) 222 require.NoError(t, err) 223 must.Eq(t, 30, updatedIndex) 224 225 // List the ACL roles in state. 226 iter, err = testState.GetACLRoles(ws) 227 require.NoError(t, err) 228 229 // Count how many table entries we have, to ensure it is the expected 230 // number. 231 count = 0 232 233 for raw := iter.Next(); raw != nil; raw = iter.Next() { 234 count++ 235 236 // Ensure the create and modify indexes are populated correctly. 237 aclRole := raw.(*structs.ACLRole) 238 must.Eq(t, 20, aclRole.CreateIndex) 239 must.Eq(t, 30, aclRole.ModifyIndex) 240 } 241 require.Equal(t, 1, count, "incorrect number of ACL roles found") 242 243 // Now try inserting an ACL role using the missing policies' argument to 244 // simulate replication. 245 replicatedACLRole := mock.ACLRole() 246 replicatedACLRole.Policies = []*structs.ACLRolePolicyLink{{Name: "nope"}} 247 require.NoError(t, testState.UpsertACLRoles( 248 structs.MsgTypeTestSetup, 40, []*structs.ACLRole{replicatedACLRole}, true)) 249 250 replicatedACLRoleResp, err := testState.GetACLRoleByName(ws, replicatedACLRole.Name) 251 require.NoError(t, err) 252 must.Eq(t, replicatedACLRole.Hash, replicatedACLRoleResp.Hash) 253 254 // Try adding a new ACL role, which has a name clash with an existing 255 // entry. 256 dupRoleName := mock.ACLRole() 257 dupRoleName.Name = mockedACLRoles[0].Name 258 259 err = testState.UpsertACLRoles(structs.MsgTypeTestSetup, 50, 260 []*structs.ACLRole{dupRoleName}, false) 261 require.ErrorContains(t, err, fmt.Sprintf("ACL role with name %s already exists", dupRoleName.Name)) 262 } 263 264 func TestStateStore_ValidateACLRolePolicyLinks(t *testing.T) { 265 ci.Parallel(t) 266 testState := testStateStore(t) 267 268 // Create our mocked role which includes two ACL policy links. 269 mockedACLRoles := []*structs.ACLRole{mock.ACLRole()} 270 271 // This should error as no policies exist within state. 272 err := testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false) 273 require.ErrorContains(t, err, "ACL policy not found") 274 275 // Upsert one ACL policy and retry the role which should still fail. 276 policy1 := mock.ACLPolicy() 277 policy1.Name = "mocked-test-policy-1" 278 279 require.NoError(t, testState.UpsertACLPolicies(structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1})) 280 err = testState.UpsertACLRoles(structs.MsgTypeTestSetup, 20, mockedACLRoles, false) 281 require.ErrorContains(t, err, "ACL policy not found") 282 283 // Upsert the second ACL policy. The ACL role should now upsert into state 284 // without error. 285 policy2 := mock.ACLPolicy() 286 policy2.Name = "mocked-test-policy-2" 287 288 require.NoError(t, testState.UpsertACLPolicies(structs.MsgTypeTestSetup, 20, []*structs.ACLPolicy{policy2})) 289 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 30, mockedACLRoles, false)) 290 } 291 292 func TestStateStore_DeleteACLRolesByID(t *testing.T) { 293 ci.Parallel(t) 294 testState := testStateStore(t) 295 296 // Create the policies our ACL roles wants to link to. 297 policy1 := mock.ACLPolicy() 298 policy1.Name = "mocked-test-policy-1" 299 policy2 := mock.ACLPolicy() 300 policy2.Name = "mocked-test-policy-2" 301 302 require.NoError(t, testState.UpsertACLPolicies( 303 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 304 305 // Generate a some mocked ACL roles for testing and upsert these straight 306 // into state. 307 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 308 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false)) 309 310 // Try and delete a role using a name that doesn't exist. This should 311 // return an error and not change the index for the table. 312 err := testState.DeleteACLRolesByID(structs.MsgTypeTestSetup, 20, []string{"not-a-role"}) 313 require.ErrorContains(t, err, "ACL role not found") 314 315 tableIndex, err := testState.Index(TableACLRoles) 316 require.NoError(t, err) 317 must.Eq(t, 10, tableIndex) 318 319 // Delete one of the previously upserted ACL roles. This should succeed 320 // and modify the table index. 321 err = testState.DeleteACLRolesByID(structs.MsgTypeTestSetup, 20, []string{mockedACLRoles[0].ID}) 322 require.NoError(t, err) 323 324 tableIndex, err = testState.Index(TableACLRoles) 325 require.NoError(t, err) 326 must.Eq(t, 20, tableIndex) 327 328 // List the ACL roles and ensure we now only have one present and that it 329 // is the one we expect. 330 ws := memdb.NewWatchSet() 331 iter, err := testState.GetACLRoles(ws) 332 require.NoError(t, err) 333 334 var aclRoles []*structs.ACLRole 335 336 for raw := iter.Next(); raw != nil; raw = iter.Next() { 337 aclRoles = append(aclRoles, raw.(*structs.ACLRole)) 338 } 339 340 require.Len(t, aclRoles, 1, "incorrect number of ACL roles found") 341 require.True(t, aclRoles[0].Equal(mockedACLRoles[1])) 342 343 // Delete the final remaining ACL role. This should succeed and modify the 344 // table index. 345 err = testState.DeleteACLRolesByID(structs.MsgTypeTestSetup, 30, []string{mockedACLRoles[1].ID}) 346 require.NoError(t, err) 347 348 tableIndex, err = testState.Index(TableACLRoles) 349 require.NoError(t, err) 350 must.Eq(t, 30, tableIndex) 351 352 // List the ACL roles and ensure we have zero entries. 353 iter, err = testState.GetACLRoles(ws) 354 require.NoError(t, err) 355 356 aclRoles = []*structs.ACLRole{} 357 358 for raw := iter.Next(); raw != nil; raw = iter.Next() { 359 aclRoles = append(aclRoles, raw.(*structs.ACLRole)) 360 } 361 require.Len(t, aclRoles, 0, "incorrect number of ACL roles found") 362 } 363 364 func TestStateStore_GetACLRoles(t *testing.T) { 365 ci.Parallel(t) 366 testState := testStateStore(t) 367 368 // Create the policies our ACL roles wants to link to. 369 policy1 := mock.ACLPolicy() 370 policy1.Name = "mocked-test-policy-1" 371 policy2 := mock.ACLPolicy() 372 policy2.Name = "mocked-test-policy-2" 373 374 require.NoError(t, testState.UpsertACLPolicies( 375 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 376 377 // Generate a some mocked ACL roles for testing and upsert these straight 378 // into state. 379 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 380 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false)) 381 382 // List the ACL roles and ensure they are exactly as we expect. 383 ws := memdb.NewWatchSet() 384 iter, err := testState.GetACLRoles(ws) 385 require.NoError(t, err) 386 387 var aclRoles []*structs.ACLRole 388 389 for raw := iter.Next(); raw != nil; raw = iter.Next() { 390 aclRoles = append(aclRoles, raw.(*structs.ACLRole)) 391 } 392 393 expected := mockedACLRoles 394 for i := range expected { 395 expected[i].CreateIndex = 10 396 expected[i].ModifyIndex = 10 397 } 398 399 require.ElementsMatch(t, aclRoles, expected) 400 } 401 402 func TestStateStore_GetACLRoleByID(t *testing.T) { 403 ci.Parallel(t) 404 testState := testStateStore(t) 405 406 // Create the policies our ACL roles wants to link to. 407 policy1 := mock.ACLPolicy() 408 policy1.Name = "mocked-test-policy-1" 409 policy2 := mock.ACLPolicy() 410 policy2.Name = "mocked-test-policy-2" 411 412 require.NoError(t, testState.UpsertACLPolicies( 413 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 414 415 // Generate a some mocked ACL roles for testing and upsert these straight 416 // into state. 417 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 418 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false)) 419 420 ws := memdb.NewWatchSet() 421 422 // Try reading an ACL role that does not exist. 423 aclRole, err := testState.GetACLRoleByID(ws, "not-a-role") 424 require.NoError(t, err) 425 require.Nil(t, aclRole) 426 427 // Read the two ACL roles that we should find. 428 aclRole, err = testState.GetACLRoleByID(ws, mockedACLRoles[0].ID) 429 require.NoError(t, err) 430 require.Equal(t, mockedACLRoles[0], aclRole) 431 432 aclRole, err = testState.GetACLRoleByID(ws, mockedACLRoles[1].ID) 433 require.NoError(t, err) 434 require.Equal(t, mockedACLRoles[1], aclRole) 435 } 436 437 func TestStateStore_GetACLRoleByName(t *testing.T) { 438 ci.Parallel(t) 439 testState := testStateStore(t) 440 441 // Create the policies our ACL roles wants to link to. 442 policy1 := mock.ACLPolicy() 443 policy1.Name = "mocked-test-policy-1" 444 policy2 := mock.ACLPolicy() 445 policy2.Name = "mocked-test-policy-2" 446 447 require.NoError(t, testState.UpsertACLPolicies( 448 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 449 450 // Generate a some mocked ACL roles for testing and upsert these straight 451 // into state. 452 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 453 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false)) 454 455 ws := memdb.NewWatchSet() 456 457 // Try reading an ACL role that does not exist. 458 aclRole, err := testState.GetACLRoleByName(ws, "not-a-role") 459 require.NoError(t, err) 460 require.Nil(t, aclRole) 461 462 // Read the two ACL roles that we should find. 463 aclRole, err = testState.GetACLRoleByName(ws, mockedACLRoles[0].Name) 464 require.NoError(t, err) 465 require.Equal(t, mockedACLRoles[0], aclRole) 466 467 aclRole, err = testState.GetACLRoleByName(ws, mockedACLRoles[1].Name) 468 require.NoError(t, err) 469 require.Equal(t, mockedACLRoles[1], aclRole) 470 } 471 472 func TestStateStore_GetACLRoleByIDPrefix(t *testing.T) { 473 ci.Parallel(t) 474 testState := testStateStore(t) 475 476 // Create the policies our ACL roles wants to link to. 477 policy1 := mock.ACLPolicy() 478 policy1.Name = "mocked-test-policy-1" 479 policy2 := mock.ACLPolicy() 480 policy2.Name = "mocked-test-policy-2" 481 482 require.NoError(t, testState.UpsertACLPolicies( 483 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 484 485 // Generate a some mocked ACL roles for testing and upsert these straight 486 // into state. Set the ID to something with a prefix we know so it is easy 487 // to test. 488 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 489 mockedACLRoles[0].ID = "test-prefix-" + uuid.Generate() 490 mockedACLRoles[1].ID = "test-prefix-" + uuid.Generate() 491 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, mockedACLRoles, false)) 492 493 ws := memdb.NewWatchSet() 494 495 // Try using a prefix that doesn't match any entries. 496 iter, err := testState.GetACLRoleByIDPrefix(ws, "nope") 497 require.NoError(t, err) 498 499 var aclRoles []*structs.ACLRole 500 for raw := iter.Next(); raw != nil; raw = iter.Next() { 501 aclRoles = append(aclRoles, raw.(*structs.ACLRole)) 502 } 503 require.Len(t, aclRoles, 0) 504 505 // Use a prefix which should match two entries in state. 506 iter, err = testState.GetACLRoleByIDPrefix(ws, "test-prefix-") 507 require.NoError(t, err) 508 509 aclRoles = []*structs.ACLRole{} 510 for raw := iter.Next(); raw != nil; raw = iter.Next() { 511 aclRoles = append(aclRoles, raw.(*structs.ACLRole)) 512 } 513 require.Len(t, aclRoles, 2) 514 } 515 516 func TestStateStore_fixTokenRoleLinks(t *testing.T) { 517 ci.Parallel(t) 518 519 testCases := []struct { 520 name string 521 testFn func() 522 }{ 523 { 524 name: "no fix needed", 525 testFn: func() { 526 testState := testStateStore(t) 527 528 // Create the policies our ACL roles wants to link to. 529 policy1 := mock.ACLPolicy() 530 policy1.Name = "mocked-test-policy-1" 531 policy2 := mock.ACLPolicy() 532 policy2.Name = "mocked-test-policy-2" 533 534 require.NoError(t, testState.UpsertACLPolicies( 535 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 536 537 // Generate a some mocked ACL roles for testing and upsert these straight 538 // into state. 539 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 540 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 20, mockedACLRoles, false)) 541 542 // Create an ACL token linking to the ACL role. 543 token1 := mock.ACLToken() 544 token1.Roles = []*structs.ACLTokenRoleLink{{ID: mockedACLRoles[0].ID}} 545 require.NoError(t, testState.UpsertACLTokens( 546 structs.MsgTypeTestSetup, 20, []*structs.ACLToken{token1})) 547 548 // Perform the fix and check the returned token contains the 549 // correct roles. 550 readTxn := testState.db.ReadTxn() 551 outputToken, err := testState.fixTokenRoleLinks(readTxn, token1) 552 require.NoError(t, err) 553 require.Equal(t, outputToken.Roles, []*structs.ACLTokenRoleLink{{ 554 Name: mockedACLRoles[0].Name, ID: mockedACLRoles[0].ID, 555 }}) 556 }, 557 }, 558 { 559 name: "acl role from link deleted", 560 testFn: func() { 561 testState := testStateStore(t) 562 563 // Create the policies our ACL roles wants to link to. 564 policy1 := mock.ACLPolicy() 565 policy1.Name = "mocked-test-policy-1" 566 policy2 := mock.ACLPolicy() 567 policy2.Name = "mocked-test-policy-2" 568 569 require.NoError(t, testState.UpsertACLPolicies( 570 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 571 572 // Generate a some mocked ACL roles for testing and upsert these straight 573 // into state. 574 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 575 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 20, mockedACLRoles, false)) 576 577 // Create an ACL token linking to the ACL roles. 578 token1 := mock.ACLToken() 579 token1.Roles = []*structs.ACLTokenRoleLink{{ID: mockedACLRoles[0].ID}, {ID: mockedACLRoles[1].ID}} 580 require.NoError(t, testState.UpsertACLTokens( 581 structs.MsgTypeTestSetup, 30, []*structs.ACLToken{token1})) 582 583 // Now delete one of the ACL roles from state. 584 require.NoError(t, testState.DeleteACLRolesByID( 585 structs.MsgTypeTestSetup, 40, []string{mockedACLRoles[0].ID})) 586 587 // Perform the fix and check the returned token contains the 588 // correct roles. 589 readTxn := testState.db.ReadTxn() 590 outputToken, err := testState.fixTokenRoleLinks(readTxn, token1) 591 require.NoError(t, err) 592 require.Len(t, outputToken.Roles, 1) 593 require.Equal(t, outputToken.Roles, []*structs.ACLTokenRoleLink{{ 594 Name: mockedACLRoles[1].Name, ID: mockedACLRoles[1].ID, 595 }}) 596 }, 597 }, 598 { 599 name: "acl role from link name changed", 600 testFn: func() { 601 testState := testStateStore(t) 602 603 // Create the policies our ACL roles wants to link to. 604 policy1 := mock.ACLPolicy() 605 policy1.Name = "mocked-test-policy-1" 606 policy2 := mock.ACLPolicy() 607 policy2.Name = "mocked-test-policy-2" 608 609 require.NoError(t, testState.UpsertACLPolicies( 610 structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})) 611 612 // Generate a some mocked ACL roles for testing and upsert these straight 613 // into state. 614 mockedACLRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()} 615 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 20, mockedACLRoles, false)) 616 617 // Create an ACL token linking to the ACL roles. 618 token1 := mock.ACLToken() 619 token1.Roles = []*structs.ACLTokenRoleLink{{ID: mockedACLRoles[0].ID}, {ID: mockedACLRoles[1].ID}} 620 require.NoError(t, testState.UpsertACLTokens( 621 structs.MsgTypeTestSetup, 30, []*structs.ACLToken{token1})) 622 623 // Now change the name of one of the ACL roles. 624 mockedACLRoles[0].Name = "badger-badger-badger" 625 require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 40, mockedACLRoles, false)) 626 627 // Perform the fix and check the returned token contains the 628 // correct roles. 629 readTxn := testState.db.ReadTxn() 630 outputToken, err := testState.fixTokenRoleLinks(readTxn, token1) 631 require.NoError(t, err) 632 require.Len(t, outputToken.Roles, 2) 633 require.ElementsMatch(t, outputToken.Roles, []*structs.ACLTokenRoleLink{ 634 {Name: mockedACLRoles[0].Name, ID: mockedACLRoles[0].ID}, 635 {Name: mockedACLRoles[1].Name, ID: mockedACLRoles[1].ID}, 636 }) 637 }, 638 }, 639 } 640 641 for _, tc := range testCases { 642 t.Run(tc.name, func(t *testing.T) { 643 tc.testFn() 644 }) 645 } 646 }