// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package ldap import ( "context" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRepository_DeleteAuthMethod(t *testing.T) { testConn, _ := db.TestSetup(t, "postgres") testRw := db.New(testConn) testWrapper := db.TestWrapper(t) testKms := kms.TestKms(t, testConn, testWrapper) testCtx := context.Background() tests := []struct { name string reader db.Reader writer db.Writer kms kms.GetWrapperer authMethod *AuthMethod wantRowsDeleted int wantErrMatch *errors.Template wantErrContains string }{ { name: "valid", reader: testRw, writer: testRw, kms: testKms, authMethod: func() *AuthMethod { org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper)) databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase) require.NoError(t, err) return TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1"}, WithOperationalState(testCtx, InactiveState)) }(), wantRowsDeleted: 1, }, { name: "no-public-id", reader: testRw, writer: testRw, kms: testKms, authMethod: func() *AuthMethod { am := AllocAuthMethod(); return &am }(), wantErrMatch: errors.T(errors.InvalidPublicId), wantErrContains: "missing public id", }, { name: "not-found", reader: testRw, writer: testRw, kms: testKms, authMethod: func() *AuthMethod { am := AllocAuthMethod() var err error am.PublicId, err = newAuthMethodId(testCtx) require.NoError(t, err) return &am }(), }, { name: "lookup-err", reader: func() db.Reader { conn, mock := db.TestSetupWithMock(t) mock.ExpectQuery(`SELECT`).WillReturnError(errors.New(context.Background(), errors.Internal, "test", "lookup-error")) return db.New(conn) }(), writer: testRw, kms: testKms, authMethod: func() *AuthMethod { org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper)) databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase) require.NoError(t, err) return TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1"}, WithOperationalState(testCtx, InactiveState)) }(), wantErrMatch: errors.T(errors.Internal), wantErrContains: "lookup-err", }, { name: "delete-err", reader: testRw, writer: func() db.Writer { conn, mock := db.TestSetupWithMock(t) mock.ExpectBegin() mock.ExpectQuery(`SELECT`).WillReturnError(errors.New(context.Background(), errors.Internal, "test", "delete-error")) mock.ExpectRollback() return db.New(conn) }(), kms: testKms, authMethod: func() *AuthMethod { org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper)) databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase) require.NoError(t, err) return TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1"}, WithOperationalState(testCtx, InactiveState)) }(), wantErrMatch: errors.T(errors.Internal), wantErrContains: "delete-err", }, { name: "multiple-rows-err", reader: testRw, writer: func() db.Writer { conn, mock := db.TestSetupWithMock(t) mock.ExpectBegin() mock.ExpectQuery(`SELECT`).WillReturnRows(sqlmock.NewRows([]string{"id", "version"}).AddRow("1", 1)) // oplog: get ticket mock.ExpectExec(`DELETE`).WillReturnResult(sqlmock.NewResult(0, 10)) mock.ExpectQuery(`INSERT`).WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("1")) // oplog: insert metadata mock.ExpectQuery(`INSERT`).WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("1")) // oplog: insert entry mock.ExpectExec(`UPDATE`).WillReturnResult(sqlmock.NewResult(0, 1)) // oplog: update ticket version mock.ExpectQuery(`SELECT`).WillReturnRows(sqlmock.NewRows([]string{"id", "version"}).AddRow("1", 1)) // oplog: get ticket again mock.ExpectRollback() return db.New(conn) }(), kms: testKms, authMethod: func() *AuthMethod { org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper)) databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase) require.NoError(t, err) return TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1"}, WithOperationalState(testCtx, InactiveState)) }(), wantErrMatch: errors.T(errors.MultipleRecords), wantErrContains: "more than 1 auth method would have been deleted", }, { name: "getWrapper-err", reader: testRw, writer: testRw, kms: &mockGetWrapperer{ getErr: errors.New(testCtx, errors.Encrypt, "test", "get-db-wrapper-err"), }, authMethod: func() *AuthMethod { org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper)) databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase) require.NoError(t, err) return TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1"}, WithOperationalState(testCtx, InactiveState)) }(), wantErrMatch: errors.T(errors.Encrypt), wantErrContains: "unable to get oplog wrapper", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) repo, err := NewRepository(testCtx, tc.reader, tc.writer, tc.kms) require.NoError(err) deletedRows, err := repo.DeleteAuthMethod(testCtx, tc.authMethod.PublicId) if tc.wantErrMatch != nil { require.Error(err) assert.Truef(errors.Match(tc.wantErrMatch, err), "want err: %q got: %q", tc.wantErrMatch.Msg, err) if tc.wantErrContains != "" { assert.Contains(err.Error(), tc.wantErrContains) } assert.Equalf(0, deletedRows, "expected 0 deleted rows and got %d", deletedRows) err := db.TestVerifyOplog(t, testRw, tc.authMethod.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) require.Errorf(err, "should not have found oplog entry for %s", tc.authMethod.PublicId) assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "expected error code %s and got %s", errors.RecordNotFound, err) return } require.NoError(err) assert.Equalf(tc.wantRowsDeleted, deletedRows, "expected rows deleted == %d and got %d", tc.wantRowsDeleted, deletedRows) if tc.wantRowsDeleted > 0 { err = db.TestVerifyOplog(t, testRw, tc.authMethod.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) require.NoErrorf(err, "unexpected error verifying oplog entry: %s", err) } found, err := repo.LookupAuthMethod(testCtx, tc.authMethod.PublicId) require.NoError(err) assert.Nil(found) }) } }