Skip to content

Commit 874659f

Browse files
authored
fix: Allow extension service reuse after soft delete (#2827)
Updates the extension service name uniqueness constraint to apply only to non-deleted services. ## Related issues <!-- Refer to existing GitHub issues here --> ## Type of Change <!-- Check one that best describes this PR --> - [ ] **Add** - New feature or capability - [ ] **Change** - Changes in existing functionality - [x] **Fix** - Bug fixes - [ ] **Remove** - Removed features or deprecated functionality - [ ] **Internal** - Internal changes (refactoring, tests, docs, etc.) ## Breaking Changes <!-- If checked, describe the breaking changes and migration steps --> <!-- Breaking changes are not generally permitted, please discuss on a GitHub discussion or with the development team if you believe you need to break a backward compatibility guarantee --> - [ ] **This PR contains breaking changes** ## Testing <!-- How was this tested? Check all that apply --> - [x] Unit tests added/updated - [ ] Integration tests added/updated - [ ] Manual testing performed - [ ] No testing required (docs, internal refactor, etc.) ## Additional Notes <!-- Any additional context, deployment notes, or reviewer guidance --> Signed-off-by: Felicity Xu <hanyux@nvidia.com>
1 parent 313a0a8 commit 874659f

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

crates/api-core/src/tests/extension_service.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,46 @@ async fn test_extension_service_creation_with_same_name(
969969
Ok(())
970970
}
971971

972+
#[crate::sqlx_test]
973+
async fn test_extension_service_recreate_same_name_after_delete(
974+
db_pool: sqlx::PgPool,
975+
) -> Result<(), eyre::Report> {
976+
let env = create_test_env(db_pool).await;
977+
978+
create_test_tenants(&env).await?;
979+
980+
let service_name = "test-service";
981+
let extension_service = create_test_extension_service(&env.api, service_name, None).await?;
982+
let service_id = extension_service.service_id.clone();
983+
984+
let delete_resp = env
985+
.api
986+
.delete_dpu_extension_service(Request::new(rpc::DeleteDpuExtensionServiceRequest {
987+
service_id: service_id.clone(),
988+
versions: vec![],
989+
}))
990+
.await;
991+
assert!(delete_resp.is_ok());
992+
993+
let find_resp = env
994+
.api
995+
.find_dpu_extension_services_by_ids(Request::new(rpc::DpuExtensionServicesByIdsRequest {
996+
service_ids: vec![service_id],
997+
}))
998+
.await;
999+
assert!(find_resp.is_ok());
1000+
assert!(find_resp.unwrap().into_inner().services.is_empty());
1001+
1002+
let recreate_resp = create_test_extension_service(&env.api, service_name, None).await;
1003+
assert!(recreate_resp.is_ok());
1004+
1005+
let recreated_service = recreate_resp.unwrap();
1006+
assert_eq!(recreated_service.service_name, service_name);
1007+
assert_ne!(recreated_service.service_id, extension_service.service_id);
1008+
1009+
Ok(())
1010+
}
1011+
9721012
#[crate::sqlx_test]
9731013
async fn test_extension_service_update(db_pool: sqlx::PgPool) -> Result<(), eyre::Report> {
9741014
let env = create_test_env(db_pool).await;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- The old unique index includes soft-deleted extesnion service rows, which
2+
-- prevents a tenant from reusing a service name after the original service
3+
-- is deleted.
4+
-- Replace the old index with a partial unique index so uniqueness constraint
5+
-- only applies to non-deleted extension services to allow recreate using same
6+
-- name after deletion.
7+
DROP INDEX IF EXISTS extension_services_tenant_lowername_unique;
8+
9+
CREATE UNIQUE INDEX extension_services_tenant_lowername_unique
10+
ON extension_services (tenant_organization_id, lower(name))
11+
WHERE deleted IS NULL;

0 commit comments

Comments
 (0)