Skip to content

chore: Data Designer e2e tests - #247

Merged
mikeknep merged 8 commits into
mainfrom
aircore-729-dd-e2e/mknepper
Jun 11, 2026
Merged

chore: Data Designer e2e tests#247
mikeknep merged 8 commits into
mainfrom
aircore-729-dd-e2e/mknepper

Conversation

@mikeknep

@mikeknep mikeknep commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

The main thing

Restores the Data Designer e2e tests. Includes a test for workloads that require Nemotron Personas data, which previously was untested at the e2e level.

Also featuring

Fixes a Files service bug. Currently you cannot delete a Fileset that has an invalid (presumably: already deleted) secret, because a StorageImpl is a prerequisite to the actual data and entity deletion, and the StorageImpl requires secrets, so when we call out to Secrets service to fetch the secret we fail with a SecretNotFoundError.

Second: currently when deleting a Fileset, we do not delete cached data, we only delete the "primary" data (when owned; we no-op for NGC and HF). <--This is expected behavior

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fileset deletion now conditionally manages underlying storage data based on backend ownership—local and S3 data are deleted; external storage is preserved.
  • Tests

    • Added comprehensive Data Designer end-to-end tests covering config preview, job execution, and LLM model integration.
    • Enhanced test infrastructure for NGC-backed testing.

mikeknep added 4 commits June 9, 2026 16:30
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
@mikeknep
mikeknep requested review from a team as code owners June 9, 2026 21:40
@mikeknep
mikeknep requested a review from matthewgrossman June 9, 2026 21:41
Comment thread e2e/conftest.py Fixed
Comment thread services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py Dismissed
Comment thread services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py Fixed
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

PR centralizes E2E fixtures (NGC API key, secret creation, nemo CLI runner) and adds storage ownership semantics. Storage configs declare whether backends own underlying data; fileset deletion conditionally deletes source data based on ownership and secret availability. New Data Designer E2E tests cover preview, job execution, seeding, and personas sampling with mock LLM providers.

Changes

Storage ownership and deletion logic

Layer / File(s) Summary
Storage ownership property contracts
packages/nmp_common/src/nmp/common/files/storage_config.py, services/core/files/tests/test_*.py
BaseStorageConfig adds owns_storage_data property (default False); LocalStorageConfig and S3StorageConfig override to True; external backends (HuggingFaceStorageConfig, NGCStorageConfig) inherit False. Unit tests validate each backend's ownership claim.
Fileset deletion with secret resolution
services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py
Delete endpoint wraps source-data deletion in error handling; if secret resolution fails and backend is marked owns_storage_data=True, returns HTTP 400; otherwise logs warning and proceeds with entity deletion only.

E2E fixtures and Data Designer coverage

Layer / File(s) Summary
Shared E2E fixture setup
e2e/conftest.py, e2e/files/test_storage_backends.py
NGC API key/secret and nemo_run CLI runner fixtures moved from per-test-module to centralized conftest.py; skip decorator and local fixtures removed from storage backend tests.
Data Designer E2E test suite
e2e/test_data_designer.py
Mock provider registration, config builder with LLM columns and samplers, dataset normalization and comparison helpers, job creation with deadline-based artifact polling, and three scenarios: simple config with mock LLMs, fileset seeding, and personas sampling via NGC personas CLI.

Possibly related PRs

  • NVIDIA-NeMo/nemo-platform#217: Retrieves the NGC fixture and skip logic that this PR moves from e2e/files/test_storage_backends.py into centralized e2e/conftest.py.

Suggested reviewers

  • mckornfield
  • crookedstorm
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning Title only mentions Data Designer e2e tests but PR also fixes Files-related bugs (secret deletion and cache data deletion). Update title to reflect both e2e tests and bug fixes, e.g., 'fix: Handle missing secrets and cached data in fileset deletion; add Data Designer e2e tests'.
Docstring Coverage ⚠️ Warning Docstring coverage is 72.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aircore-729-dd-e2e/mknepper

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@e2e/conftest.py`:
- Around line 258-266: The runner currently returns the raw subprocess.run
CompletedProcess (the subprocess.run call) which hides non-zero exits; change
the call to fail fast by enabling subprocess.check behavior—either add
check=True to the subprocess.run invocation or capture the result and call
result.check_returncode() and re-raise subprocess.CalledProcessError so callers
get an exception on CLI failures; update the subprocess.run call site (the
CompletedProcess-returning call in e2e/conftest.py) accordingly and ensure
callers expect exceptions instead of relying on return codes.

In `@e2e/test_data_designer.py`:
- Around line 245-250: The current assertions using all(...) can pass vacuously
when no rows are produced; update the test around sdk.data_designer.preview
(preview_results) and _create_job_and_get_dataset (job_dataset) to first assert
that the produced datasets are non-empty (e.g., check preview_results.dataset
and job_dataset or assert len(_get_demo_ages(...)) > 0) and then run the
existing range checks using all(25 <= age <= 45 for age in _get_demo_ages(...));
reference preview_results, job_dataset, _get_demo_ages,
_create_job_and_get_dataset, sdk.data_designer.preview, workspace, and
config_builder when locating the assertions.

In `@services/core/files/src/nmp/core/files/api/endpoint_helpers.py`:
- Around line 375-377: The code calls
default_storage_config.copy_config(cache_prefix) and then
cache_storage.delete_all() without validating cache_prefix, allowing
path-traversal (e.g., '..' or absolute paths); before creating cache_scope,
validate/sanitize cache_prefix in the endpoint helper: reject or normalize
values that are empty, absolute (leading slash), contain parent-segments ('..')
or backslashes, or resolve outside the intended cache root (use a
PurePosixPath-like check), and raise/log an error or return a 4xx response
instead of proceeding; update the logic around
default_storage_config.copy_config(cache_prefix), storage_impl_factory(...) and
cache_storage.delete_all() to only run when the sanitized/validated cache_prefix
is safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fa393b3f-0e9e-4da1-b6b8-5d0bdf69eeba

📥 Commits

Reviewing files that changed from the base of the PR and between fb08b43 and 3f57399.

📒 Files selected for processing (14)
  • e2e/conftest.py
  • e2e/files/test_storage_backends.py
  • e2e/test_data_designer.py
  • packages/nmp_common/src/nmp/common/files/storage_config.py
  • services/core/files/src/nmp/core/files/api/endpoint_helpers.py
  • services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py
  • services/core/files/src/nmp/core/files/app/backends/huggingface.py
  • services/core/files/src/nmp/core/files/app/backends/ngc.py
  • services/core/files/src/nmp/core/files/app/backends/s3.py
  • services/core/files/tests/test_endpoint_helpers.py
  • services/core/files/tests/test_huggingface_backend.py
  • services/core/files/tests/test_local_backend.py
  • services/core/files/tests/test_ngc_backend.py
  • services/core/files/tests/test_s3_backend.py
💤 Files with no reviewable changes (1)
  • e2e/files/test_storage_backends.py

Comment thread e2e/conftest.py
Comment thread e2e/test_data_designer.py
Comment thread services/core/files/src/nmp/core/files/api/endpoint_helpers.py Outdated
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 19034/25088 75.9% 62.4%
Integration Tests 12038/23860 50.4% 25.6%

mikeknep added 2 commits June 9, 2026 16:58
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
@mikeknep
mikeknep force-pushed the aircore-729-dd-e2e/mknepper branch from 8c31455 to c55ba30 Compare June 9, 2026 22:11
Comment thread e2e/conftest.py
Comment thread services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py Outdated
Comment thread packages/nmp_common/src/nmp/common/files/storage_config.py
mikeknep added 2 commits June 10, 2026 08:56
Signed-off-by: Mike Knepper <mknepper@nvidia.com>
Signed-off-by: Mike Knepper <mknepper@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py (1)

417-423: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate source deletion on ownership before secret resolution.

Line 420–422 still resolves secrets and calls delete_all() for external backends. That relies on backend no-op behavior instead of enforcing the ownership contract at the endpoint.

Proposed fix
-    try:
-        secrets = await resolve_storage_secrets_for_user(fileset.storage, workspace, sdk, auth_client)
-        storage = storage_impl_factory(fileset.storage, secrets)
-        await storage.delete_all()
-    except (SecretNotFoundError, SecretAccessDeniedError) as exc:
+    if fileset.storage.owns_storage_data:
+        try:
+            secrets = await resolve_storage_secrets_for_user(fileset.storage, workspace, sdk, auth_client)
+            storage = storage_impl_factory(fileset.storage, secrets)
+            await storage.delete_all()
+        except (SecretNotFoundError, SecretAccessDeniedError) as exc:
             # For backends we own (local, S3), the secret is required to delete the source
             # data; silently skipping that would orphan data we're responsible for. Surface
             # it. For external backends (NGC, HuggingFace) the source isn't ours to delete,
             # so a missing secret must not block removing the fileset - proceed.
-        if fileset.storage.owns_storage_data:
             logger.error(
                 f"Cannot delete owned source data for fileset '{workspace}/{name}' "
                 f"because its storage secret is unavailable: {exc}"
             )
             raise HTTPException(
                 HTTP_400_BAD_REQUEST,
                 f"Cannot delete fileset '{workspace}/{name}': its storage secret is "
                 f"unavailable, so the underlying data cannot be removed. Restore the "
                 f"secret and retry. ({exc})",
             ) from exc
-        logger.warning(
-            f"Storage secret unavailable while deleting external fileset '{workspace}/{name}'; "
-            f"nothing to delete on the source, proceeding with entity deletion: {exc}"
-        )
+    else:
+        logger.info(
+            f"Skipping source-data deletion for external fileset '{workspace}/{name}' "
+            f"(storage is not platform-owned)."
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py` around
lines 417 - 423, The endpoint currently calls resolve_storage_secrets_for_user
and storage_impl_factory then storage.delete_all for all backends; instead,
first check ownership of the fileset/storage and only resolve secrets and call
storage.delete_all for backends we own. Update the code around fileset.storage
handling to perform an ownership gate (e.g., verify fileset is owned by the
workspace or that the backend is not external) before invoking
resolve_storage_secrets_for_user(fileset.storage, ...) and
storage_impl_factory(...)/storage.delete_all(), leaving external backends as a
no-op and avoiding secret resolution for them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py`:
- Around line 417-423: The endpoint currently calls
resolve_storage_secrets_for_user and storage_impl_factory then
storage.delete_all for all backends; instead, first check ownership of the
fileset/storage and only resolve secrets and call storage.delete_all for
backends we own. Update the code around fileset.storage handling to perform an
ownership gate (e.g., verify fileset is owned by the workspace or that the
backend is not external) before invoking
resolve_storage_secrets_for_user(fileset.storage, ...) and
storage_impl_factory(...)/storage.delete_all(), leaving external backends as a
no-op and avoiding secret resolution for them.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7ff0b38f-dfb2-488e-92f5-3d178d3e707c

📥 Commits

Reviewing files that changed from the base of the PR and between c55ba30 and f75c3f3.

📒 Files selected for processing (7)
  • e2e/test_data_designer.py
  • packages/nmp_common/src/nmp/common/files/storage_config.py
  • services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py
  • services/core/files/tests/test_huggingface_backend.py
  • services/core/files/tests/test_local_backend.py
  • services/core/files/tests/test_ngc_backend.py
  • services/core/files/tests/test_s3_backend.py
💤 Files with no reviewable changes (5)
  • services/core/files/tests/test_ngc_backend.py
  • packages/nmp_common/src/nmp/common/files/storage_config.py
  • services/core/files/tests/test_huggingface_backend.py
  • services/core/files/tests/test_s3_backend.py
  • e2e/test_data_designer.py

Comment thread services/core/files/src/nmp/core/files/api/v2/filesets/endpoints.py Dismissed
@github-actions github-actions Bot added the chore label Jun 11, 2026
@mikeknep
mikeknep added this pull request to the merge queue Jun 11, 2026
Merged via the queue into main with commit af56203 Jun 11, 2026
73 of 74 checks passed
@mikeknep
mikeknep deleted the aircore-729-dd-e2e/mknepper branch June 11, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants