Skip to content

Add Tests for Exp-Type, Model and Term settings support in Bulk API and Cluster support in datasources#2013

Open
khansaad wants to merge 2 commits into
kruize:runtimes-iirjfrom
khansaad:test-cluster-support
Open

Add Tests for Exp-Type, Model and Term settings support in Bulk API and Cluster support in datasources#2013
khansaad wants to merge 2 commits into
kruize:runtimes-iirjfrom
khansaad:test-cluster-support

Conversation

@khansaad

@khansaad khansaad commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Description

This PR contains tests for the exp-type, model and term settings support in Bulk API along with cluster support in datasources.
Fixes # (issue)

Type of change

  • Bug fix
  • New feature
  • Docs update
  • Breaking change (What changes might users need to make in their application due to this PR?)
  • Requires DB changes

How has this been tested?

Please describe the tests that were run to verify your changes and steps to reproduce. Please specify any test configuration required.

  • New Test X
  • Functional testsuite

Test Configuration

  • Kubernetes clusters tested on:

Checklist 🎯

  • Followed coding guidelines
  • Comments added
  • Dependent changes merged
  • Documentation updated
  • Tests added or updated

Additional information

Include any additional information such as links, test results, screenshots here

Summary by Sourcery

Extend bulk API and datasource support for clusters and experiment types, and validate and expose these through new tests and documentation.

New Features:

  • Introduce optional cluster_name, model_settings, term_settings, and experiment_types fields in bulk API payloads and propagate them into created experiments.
  • Add namespace-level experiment creation alongside existing container-level experiments in the bulk job manager.
  • Persist and expose datasource cluster associations via a new JSONB clusters column and list-datasources API response.
  • Add new recommendation notifications for under- and over-provisioned CPU and memory requests.

Enhancements:

  • Add validation logic for bulk API cluster_name, model_settings, term_settings, and experiment_types inputs, preserving backward compatibility.
  • Enhance recommendation engine to emit provisioning status notices when generated request values differ significantly from current settings.
  • Extend datasource tests to cover cluster configuration, API exposure, and validation.
  • Document bulk API extensions and datasource cluster configuration, including behavior and use cases.

Documentation:

  • Update bulk API and datasource design docs to describe new cluster-related fields, model/term settings, and notification codes.

Tests:

  • Add Python bulk API tests for cluster_name, model_settings, term_settings, experiment_types, and backward compatibility behavior.
  • Add Java unit tests for bulk service validation, bulk job manager cluster passthrough, and datasource cluster JSONB parsing.
  • Extend shell-based local monitoring datasource tests to validate cluster information via the /datasources endpoint.

Chores:

  • Introduce a database migration to add the clusters JSONB column to the kruize_datasources table.

@sourcery-ai

sourcery-ai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds cluster-aware datasource support and new bulk API controls (cluster_name, model_settings, term_settings, experiment_types) with validation, plus namespace-level experiments, updated recommendation notifications, and comprehensive tests and docs.

Sequence diagram for bulk API experiment types and cluster override

sequenceDiagram
    actor User
    participant BulkAPI as BulkInput
    participant Validator as BulkServiceValidation
    participant Manager as BulkJobManager

    User->>BulkAPI: POST bulk payload
    BulkAPI->>Validator: validate(payload, jobID)
    Validator-->>BulkAPI: ValidationOutputData
    alt [validation passed]
        BulkAPI->>Manager: getExperimentMap(labelString, jobData, metadataInfo, datasource)
        Manager->>Manager: resolveExperimentType(experiment_types)
        loop datasources/clusters/namespaces
            alt [resolvedType == NAMESPACE]
                Manager->>Manager: frameNamespaceExperimentName(labelString, dsc, namespace)
                Manager->>Manager: prepareNamespaceExperimentJSONInput(dsc, namespace, experiment_name, list)
            else [resolvedType == CONTAINER]
                Manager->>Manager: frameExperimentName(labelString, dsc, namespace, dsw, dc)
                Manager->>Manager: prepareCreateExperimentJSONInput(dc, dsc, dsw, namespace, experiment_name, list)
            end
        end
    end
Loading

File-Level Changes

Change Details Files
Add validation and tests for new bulk API fields (cluster_name, model_settings, term_settings, experiment_types) including backward compatibility.
  • Extend BulkInput with cluster_name, model_settings, term_settings, and experiment_types fields and include them in isEmpty checks.
  • Add BulkServiceValidation logic for cluster_name length/emptiness, model_settings.models and term_settings.terms contents, and experiment_types validity against a fixed allow-list.
  • Add pytest bulk API tests to cover valid and invalid cluster_name, model_settings, term_settings, experiment_types, combined usage, and backward compatibility scenarios.
  • Add JUnit tests for BulkServiceValidation cluster_name helper to cover null, whitespace, max-length, and formatting edge cases.
src/main/java/com/autotune/analyzer/serviceObjects/BulkInput.java
src/main/java/com/autotune/common/bulk/BulkServiceValidation.java
src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java
tests/scripts/local_monitoring_tests/rest_apis/test_bulkAPI.py
src/test/java/com/autotune/common/bulk/BulkServiceValidationTest.java
Propagate bulk payload settings into experiment creation, including namespace-level experiments and experiment_types resolution.
  • Resolve a single ExperimentType per bulk job from experiment_types with default to CONTAINER and graceful fallback on invalid input.
  • Add namespace-level experiment creation path in BulkJobManager including experiment naming, Kubernetes object shaping, and experimentType metadata.
  • Pass cluster_name (trimmed), model_settings, and term_settings from BulkInput into CreateExperimentAPIObject recommendation settings while preserving legacy behavior when fields are absent.
  • Add a BulkJobManager passthrough JUnit test verifying cluster_name handling and backward compatibility of experiment naming.
src/main/java/com/autotune/analyzer/workerimpl/BulkJobManager.java
src/main/java/com/autotune/analyzer/kruizeObject/RecommendationSettings.java
src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java
src/test/java/com/autotune/analyzer/workerimpl/BulkJobManagerPassthroughTest.java
Introduce datasource cluster association stored in DB and exposed via APIs, with tests and docs.
  • Extend KruizeDataSourceEntry with a JSONB clusters column plus getter that parses to List using Utils.parseClusterList.
  • Update DataSourceInfo to carry a clusters list, including new constructor and getter, and ensure DBHelpers converts between DB and in-memory representations.
  • Parse clusters from datasource config JSON when loading datasources and inject into DataSourceInfo, validating and trimming entries.
  • Expose clusters in list-datasources API via a custom Gson DataSourceInfoAdapter that omits empty cluster lists, and add shell/integration tests to validate clusters in responses.
  • Add a Flyway migration to add the clusters JSONB column and update KruizeDatasource design docs with cluster configuration semantics and examples.
src/main/java/com/autotune/database/table/KruizeDataSourceEntry.java
src/main/java/com/autotune/common/datasource/DataSourceInfo.java
src/main/java/com/autotune/common/datasource/DataSourceCollection.java
src/main/java/com/autotune/database/helper/DBHelpers.java
src/main/java/com/autotune/utils/Utils.java
src/main/java/com/autotune/analyzer/services/ListDatasources.java
src/main/java/com/autotune/analyzer/adapters/DataSourceInfoAdapter.java
tests/scripts/local_monitoring_tests/datasource_tests.sh
design/KruizeDatasource.md
migrations/lm/v111__add_cluster_to_datasources.sql
src/test/java/com/autotune/database/table/KruizeDataSourceEntryTest.java
Enhance recommendation engine notifications to indicate CPU/Memory under- or over-provisioning and document new codes.
  • Add new RecommendationNotification enum entries and codes for CPU_REQUESTS_UNDER_PROVISIONED / OVER_PROVISIONED and MEMORY_REQUESTS_UNDER_PROVISIONED / OVER_PROVISIONED.
  • Update RecommendationEngine to emit the new notifications when request thresholds are exceeded and recommendations imply under- or over-provisioning.
  • Update NotificationCodes design documentation table to include new notification IDs and messages.
src/main/java/com/autotune/analyzer/recommendations/RecommendationConstants.java
src/main/java/com/autotune/analyzer/recommendations/engine/RecommendationEngine.java
design/NotificationCodes.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai 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.

Hey - I've found 4 issues, and left some high level feedback:

  • The error messages in BulkServiceValidation (e.g., for cluster_name length and invalid experiment_types) do not match the strings asserted in the new Python bulk API tests; consider aligning the Java message templates with the test expectations to avoid brittle failures.
  • DataSourceInfoAdapter serializes the authentication field as "authenticationConfig"; if existing consumers expect the previous JSON shape, you may want to keep the original key name or add a compatibility path to avoid changing the ListDatasources API contract.
  • BulkJobManagerPassthroughTest mostly asserts mocked BulkInput getters and does not drive BulkJobManager methods that use cluster_name/model_settings/term_settings; consider extending it to call prepareCreateExperimentJSONInput/namespace experiment creation to verify real passthrough behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The error messages in BulkServiceValidation (e.g., for cluster_name length and invalid experiment_types) do not match the strings asserted in the new Python bulk API tests; consider aligning the Java message templates with the test expectations to avoid brittle failures.
- DataSourceInfoAdapter serializes the authentication field as "authenticationConfig"; if existing consumers expect the previous JSON shape, you may want to keep the original key name or add a compatibility path to avoid changing the ListDatasources API contract.
- BulkJobManagerPassthroughTest mostly asserts mocked BulkInput getters and does not drive BulkJobManager methods that use cluster_name/model_settings/term_settings; consider extending it to call prepareCreateExperimentJSONInput/namespace experiment creation to verify real passthrough behavior.

## Individual Comments

### Comment 1
<location path="tests/scripts/local_monitoring_tests/rest_apis/test_bulkAPI.py" line_range="424-432" />
<code_context>
+@pytest.mark.parametrize("model_settings, expected_status, expected_error", [
</code_context>
<issue_to_address>
**suggestion (testing):** Extend model_settings tests to cover null/blank model names and detailed error paths

`validateModelSettings` has additional branches that aren’t yet covered by this parametrization:
- `models` containing `null` entries (should return `"model_settings.models contains null or empty model name"`).
- `models` containing blank/whitespace-only names.
- Invalid models where the error message includes both the invalid value and the list of valid models.

Please add cases like `{"models": [None]}`, `{"models": [" "]}`, and an invalid model asserting on the full error message, so the tests fully exercise these paths and guard against regressions in error formatting.

Suggested implementation:

```python
@pytest.mark.test_bulk_api_ros
@pytest.mark.parametrize("model_settings, expected_status, expected_error", [
    ({"models": ["performance"]}, SUCCESS_200_STATUS_CODE, None),  # Valid single model
    ({"models": ["cost"]}, SUCCESS_200_STATUS_CODE, None),  # Valid cost model
    ({"models": ["performance", "cost"]}, SUCCESS_200_STATUS_CODE, None),  # Valid multiple models
    ({"models": ["Performance", "COST"]}, SUCCESS_200_STATUS_CODE, None),  # Valid case-insensitive
    ({"models": []}, ERROR_STATUS_CODE, "model_settings.models cannot be null or empty"),  # Empty list
    ({"models": [None]}, ERROR_STATUS_CODE, "model_settings.models contains null or empty model name"),  # Null model name
    ({"models": [" "]}, ERROR_STATUS_CODE, "model_settings.models contains null or empty model name"),  # Blank/whitespace model name
    ({"models": ["invalid"]}, ERROR_STATUS_CODE, "Invalid model name 'invalid'. Valid models are: ['performance', 'cost']"),  # Invalid model with full error
    ({"models": ["performance", "invalid"]}, ERROR_STATUS_CODE, "Invalid model name"),  # Mixed valid/invalid
    ({}, ERROR_STATUS_CODE, "model_settings.models cannot be null or empty"),  # Missing models field
])
def test_bulk_api_model_settings_validation(cluster_type, model_settings, expected_status, expected_error, caplog):

```

If the actual implementation of `validateModelSettings` uses a slightly different error message format (for example different punctuation, ordering, or representation of the valid models list), you should adjust the two new `expected_error` strings to exactly match the real messages:
1. The "contains null or empty model name" string for `{"models": [None]}` and `{"models": [" "]}`.
2. The full invalid-model error for `{"models": ["invalid"]}`, including the precise formatting of the valid-models list.
</issue_to_address>

### Comment 2
<location path="tests/scripts/local_monitoring_tests/rest_apis/test_bulkAPI.py" line_range="464-473" />
<code_context>
+@pytest.mark.parametrize("term_settings, expected_status, expected_error", [
</code_context>
<issue_to_address>
**suggestion (testing):** Add term_settings cases for null/blank term entries and ensure error messages are asserted

`validateTermSettings` also has a branch for null/blank term entries, which isn’t covered by the current parametrization. Please add cases for:
- `{"terms": [None]}`
- `{"terms": ["   "]}`
expecting the "term_settings.terms contains null or empty term name" message.

Additionally, for at least one invalid-term case, assert on the full error message (including the valid-term list) to lock in the error contract.

Suggested implementation:

```python
        message = response.json()["message"]
        if expected_full_error:
            assert message == expected_full_error, \
                f"Expected error message to be '{expected_full_error}' but got: {message}"
        elif expected_error:
            assert expected_error in message, \
                f"Expected error message to contain '{expected_error}' but got: {message}"
        else:
            # Valid model settings should create a job
            assert "job_id" in response.json(), "Expected job_id in response for valid model_settings"


@pytest.mark.test_bulk_api_ros
@pytest.mark.parametrize("term_settings, expected_status, expected_error, expected_full_error", [
    ({"terms": ["short"]}, SUCCESS_200_STATUS_CODE, None, None),  # Valid single term
    ({"terms": ["medium"]}, SUCCESS_200_STATUS_CODE, None, None),  # Valid medium term
    ({"terms": ["long"]}, SUCCESS_200_STATUS_CODE, None, None),  # Valid long term
    ({"terms": ["short", "long"]}, SUCCESS_200_STATUS_CODE, None, None),  # Valid multiple terms
    ({"terms": ["Short", "LONG"]}, SUCCESS_200_STATUS_CODE, None, None),  # Valid case-insensitive
    ({"terms": ["short", "medium", "long"]}, SUCCESS_200_STATUS_CODE, None, None),  # All terms
    ({"terms": []}, ERROR_STATUS_CODE, "term_settings.terms cannot be null or empty", None),  # Empty list
    ({"terms": [None]}, ERROR_STATUS_CODE, "term_settings.terms contains null or empty term name", None),  # Null term entry
    ({"terms": ["   "]}, ERROR_STATUS_CODE, "term_settings.terms contains null or empty term name", None),  # Blank term entry
    ({"terms": ["invalid"]}, ERROR_STATUS_CODE, "Invalid term name", "Invalid term name. Valid terms are: short, medium, long"),  # Invalid term with full error
    ({"terms": ["short", "invalid"]}, ERROR_STATUS_CODE, "Invalid term name", None),  # Mixed valid/invalid
    ({}, ERROR_STATUS_CODE, "term_settings.terms cannot be null or empty", None),  # Missing terms field

```

1. Ensure the test function that consumes these parameters is updated to accept the new `expected_full_error` argument in its signature (e.g., `def test_...(..., expected_status, expected_error, expected_full_error, ...)`).
2. If the actual full error message for invalid terms differs from `"Invalid term name. Valid terms are: short, medium, long"`, adjust the `expected_full_error` string in the parametrization to exactly match the implementation's message, including punctuation and spacing.
</issue_to_address>

### Comment 3
<location path="design/KruizeDatasource.md" line_range="388-389" />
<code_context>
+}
+```
+
+#### Multiple Clusters Example
+TBA
+
+### Behavior
</code_context>
<issue_to_address>
**issue:** Complete or clarify the 'Multiple Clusters Example' section instead of leaving 'TBA'.

Since this section is user-facing, please either add a concrete multi-cluster configuration example or clearly note that it will be documented once full multi-cluster support is available. Leaving it as-is makes the document appear unfinished and may confuse readers.
</issue_to_address>

### Comment 4
<location path="design/NotificationCodes.md" line_range="86-92" />
<code_context>
+| 323007 |  NOTICE  |     CPU_REQUESTS_OVER_PROVISIONED     |        Specifies that the workload is over-provisioned for CPU requests         |    Workload is over-provisioned for CPU. Kruize recommends reducing CPU allocation to optimize costs.    | DATA USER |
</code_context>
<issue_to_address>
**nitpick (typo):** Align spelling of 'optimise/optimize' for consistency across the notification descriptions.

These new rows use 'optimize costs', while existing entries (e.g., OPTIMISED) use 'optimised'. Please standardize on either US or UK spelling across the table for consistency, unless the difference is intentional.

Suggested implementation:

```
| 323007 |  NOTICE  |     CPU_REQUESTS_OVER_PROVISIONED     |        Specifies that the workload is over-provisioned for CPU requests         |    Workload is over-provisioned for CPU. Kruize recommends reducing CPU allocation to optimise costs.    | DATA USER |

```

```
| 324006 |  NOTICE  |   MEMORY_REQUESTS_OVER_PROVISIONED    |       Specifies that the workload is over-provisioned for Memory requests       | Workload is over-provisioned for Memory. Kruize recommends reducing Memory allocation to optimise costs. | DATA USER |

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread tests/scripts/local_monitoring_tests/rest_apis/test_bulkAPI.py Outdated
Comment thread tests/scripts/local_monitoring_tests/rest_apis/test_bulkAPI.py Outdated
Comment thread design/KruizeDatasource.md Outdated
Comment thread design/NotificationCodes.md Outdated
Signed-off-by: Saad Khan <saakhan@ibm.com>
@khansaad
khansaad force-pushed the test-cluster-support branch from 996c9b8 to 140f780 Compare July 8, 2026 11:43
@khansaad khansaad moved this to In Progress in Monitoring Jul 9, 2026
@khansaad khansaad changed the title Add Tests for Cluster support in Datasource Add Tests for Exp-Type, Model and Term settings support in Bulk API Jul 9, 2026
@khansaad khansaad changed the title Add Tests for Exp-Type, Model and Term settings support in Bulk API Add Tests for Exp-Type, Model and Term settings support in Bulk API and Cluster support in datasources Jul 9, 2026
Signed-off-by: Saad Khan <saakhan@ibm.com>
@khansaad khansaad moved this from In Progress to Under Review in Monitoring Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Under Review

Development

Successfully merging this pull request may close these issues.

1 participant