Skip to content

Conversation

@edgarrmondragon
Copy link
Collaborator

@edgarrmondragon edgarrmondragon commented Sep 18, 2025

Summary

  • Added comprehensive tests for the new streams parameter in TapTestRunner
  • Fixed existing factory tests to accommodate the new parameter

Test Coverage Added

  • TapTestRunner initialization with streams parameter (list, tuple, empty, None)
  • run_sync_dry_run method with streams parameter
  • Integration test for complete workflow with streams
  • Compatibility with other initialization arguments

Changes Made

  • tests/core/testing/test_runners.py: Added 7 new test methods for streams parameter
  • tests/core/testing/test_factory.py: Updated 3 existing tests to include streams=None parameter

Test Plan

  • All new tests pass
  • All existing tests in test_runners.py pass (38 tests total)
  • All existing tests in test_factory.py pass (23 tests total)
  • No breaking changes to existing functionality

🤖 Generated with Claude Code

Summary by Sourcery

Introduce a 'streams' parameter to TapTestRunner and propagate it through the testing factory and runner, extend run_sync_dry_run to filter streams by name or object, and add comprehensive tests for streams behavior.

New Features:

  • Support passing a 'streams' parameter to TapTestRunner to limit which streams are processed during dry-run execution
  • Expose the 'streams' parameter in testing factory functions new_test_class and get_tap_test_class

Enhancements:

  • Extend TapBase.run_sync_dry_run to accept stream names or objects and select them correctly before running the dry run

Tests:

  • Add unit tests for TapTestRunner initialization with streams as list, tuple, empty sequence, and None
  • Add tests for run_sync_dry_run with and without streams parameter and with other kwargs
  • Add an integration-style test covering a full TapTestRunner workflow using the streams parameter
  • Update existing test_factory tests to include the new streams argument

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Sep 18, 2025

Reviewer's Guide

This PR adds a new streams parameter to TapTestRunner by propagating it through runner initialization and execution paths, enhances the core run_sync_dry_run implementation to resolve stream names, updates testing factory helpers to accept streams, and augments tests to fully cover the new behavior.

File-Level Changes

Change Details Files
Propagate 'streams' parameter through TapTestRunner
  • Added streams keyword argument to TapTestRunner.init and stored as self.streams
  • Updated run_sync_dry_run to pass streams=self.streams to the tap
singer_sdk/testing/runners.py
Enhance Tap.run_sync_dry_run to accept and resolve stream names
  • Updated method signature to allow Iterable[Stream
str]
  • Added logic to map string names to stream instances and collect selected_streams
  • Iterated over resolved streams list rather than raw input
  • Extend testing factory to support streams parameter
    • Added streams parameter to new_test_class and get_tap_test_class signatures
    • Passed streams argument when instantiating TapTestRunner via factory
    singer_sdk/testing/factory.py
    Add tests covering TapTestRunner 'streams' parameter
    • Added tests for initialization with list, tuple, empty, None
    • Added tests for run_sync_dry_run call with streams variants
    • Added integration-style full workflow test including streams
    • Modified existing dry run test to assert default streams=None
    tests/core/testing/test_runners.py
    Update factory tests to include streams parameter
    • Updated default suite factory tests to pass streams=None
    • Adjusted custom kwargs factory tests to include streams
    • Updated get_tap_test_class tests to include streams
    tests/core/testing/test_factory.py

    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

    @edgarrmondragon edgarrmondragon changed the title test: Add comprehensive tests for TapTestRunner streams parameter feat: Select streams for testing Sep 18, 2025
    @edgarrmondragon edgarrmondragon self-assigned this Sep 18, 2025
    @read-the-docs-community
    Copy link

    read-the-docs-community bot commented Sep 18, 2025

    Documentation build overview

    📚 Meltano SDK | 🛠️ Build #29988956 | 📁 Comparing fca9043 against latest (ef953f5)


    🔍 Preview build

    Show files changed (3 files in total): 📝 3 modified | ➕ 0 added | ➖ 0 deleted
    File Status
    testing.html 📝 modified
    classes/singer_sdk.SQLTap.html 📝 modified
    classes/singer_sdk.Tap.html 📝 modified

    Copy link
    Contributor

    @sourcery-ai sourcery-ai bot left a comment

    Choose a reason for hiding this comment

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

    Hey there - I've reviewed your changes and they look great!

    Prompt for AI Agents
    Please address the comments from this code review:
    
    ## Individual Comments
    
    ### Comment 1
    <location> `tests/core/testing/test_runners.py:181-190` </location>
    <code_context>
    +            streams=None,
             )
    
    +    def test_init_with_streams_parameter(self, mock_tap_class):
    +        """Test TapTestRunner initialization with streams parameter."""
    +        config = {"test": "config"}
    +        streams = ["users", "orders", "products"]
    +
    +        runner = TapTestRunner(
    +            tap_class=mock_tap_class,
    +            config=config,
    +            streams=streams,
    +        )
    +
    +        assert runner.streams == streams
    +        assert runner.singer_class is mock_tap_class
    +        assert runner.config == config
    +
    +    def test_init_with_streams_none(self, mock_tap_class):
    </code_context>
    
    <issue_to_address>
    **suggestion (testing):** Consider adding tests for invalid or unexpected types for the streams parameter.
    
    Adding tests for invalid types, such as integers, dicts, or lists with non-string/non-Stream elements, will improve error handling and type safety for the streams parameter.
    
    Suggested implementation:
    
    ```python
        def test_init_with_streams_empty_sequence(self, mock_tap_class):
            """Test TapTestRunner initialization with empty streams sequence."""
    
        def test_init_with_streams_invalid_type_int(self, mock_tap_class):
            """Test TapTestRunner initialization with streams as an integer."""
            config = {"test": "config"}
            streams = 123  # Invalid type
    
            with pytest.raises(TypeError):
                TapTestRunner(
                    tap_class=mock_tap_class,
                    config=config,
                    streams=streams,
                )
    
        def test_init_with_streams_invalid_type_dict(self, mock_tap_class):
            """Test TapTestRunner initialization with streams as a dict."""
            config = {"test": "config"}
            streams = {"users": True}  # Invalid type
    
            with pytest.raises(TypeError):
                TapTestRunner(
                    tap_class=mock_tap_class,
                    config=config,
                    streams=streams,
                )
    
        def test_init_with_streams_invalid_list_elements(self, mock_tap_class):
            """Test TapTestRunner initialization with streams as a list of non-string elements."""
            config = {"test": "config"}
            streams = [123, None, object()]  # Invalid elements
    
            with pytest.raises(TypeError):
                TapTestRunner(
                    tap_class=mock_tap_class,
                    config=config,
                    streams=streams,
                )
    
    ```
    
    These tests assume that `TapTestRunner` raises a `TypeError` when invalid types are passed to the `streams` parameter. If it currently does not, you will need to add type checking and exception raising logic to the `TapTestRunner` implementation to ensure these tests pass.
    </issue_to_address>
    
    ### Comment 2
    <location> `tests/core/testing/test_runners.py:213-231` </location>
    <code_context>
    +
    +        assert runner.streams == []
    +
    +    def test_run_sync_dry_run_with_streams(self, mock_tap_class):
    +        """Test run_sync_dry_run method with streams parameter."""
    +        streams = ["users", "orders"]
    +        runner = TapTestRunner(
    +            tap_class=mock_tap_class,
    +            streams=streams,
    +        )
    +
    +        mock_tap = Mock(spec=Tap)
    +        mock_tap.run_sync_dry_run.return_value = True
    +
    +        with patch.object(runner, "new_tap", return_value=mock_tap):
    +            result = runner.run_sync_dry_run()
    +
    +        assert result is True
    +        mock_tap.run_sync_dry_run.assert_called_once_with(
    +            dry_run_record_limit=runner.suite_config.max_records_limit,
    +            streams=streams,
    </code_context>
    
    <issue_to_address>
    **suggestion (testing):** Add a test for run_sync_dry_run when streams is an empty sequence.
    
    Please add a test to confirm run_sync_dry_run behaves correctly when streams is empty, ensuring no sync is attempted.
    
    ```suggestion
    
        def test_run_sync_dry_run_with_streams(self, mock_tap_class):
            """Test run_sync_dry_run method with streams parameter."""
            streams = ["users", "orders"]
            runner = TapTestRunner(
                tap_class=mock_tap_class,
                streams=streams,
            )
    
            mock_tap = Mock(spec=Tap)
            mock_tap.run_sync_dry_run.return_value = True
    
            with patch.object(runner, "new_tap", return_value=mock_tap):
                result = runner.run_sync_dry_run()
    
            assert result is True
            mock_tap.run_sync_dry_run.assert_called_once_with(
                dry_run_record_limit=runner.suite_config.max_records_limit,
                streams=streams,
            )
    
        def test_run_sync_dry_run_with_empty_streams(self, mock_tap_class):
            """Test run_sync_dry_run method with empty streams sequence."""
            runner = TapTestRunner(
                tap_class=mock_tap_class,
                streams=[],
            )
    
            mock_tap = Mock(spec=Tap)
            mock_tap.run_sync_dry_run.return_value = True
    
            with patch.object(runner, "new_tap", return_value=mock_tap):
                result = runner.run_sync_dry_run()
    
            # Expect no sync to be attempted, so run_sync_dry_run should not be called
            assert result is None or result is False
            mock_tap.run_sync_dry_run.assert_not_called()
    ```
    </issue_to_address>
    
    ### Comment 3
    <location> `tests/core/testing/test_factory.py:139-140` </location>
    <code_context>
                 tap_class=factory.tap_class,
                 config=factory.config,
                 suite_config=None,
    +            streams=None,
                 parse_env_config=True,
             )
    
    </code_context>
    
    <issue_to_address>
    **suggestion (testing):** Consider parametrizing tests for the streams argument in factory methods.
    
    Parametrizing the tests will allow you to easily cover additional valid stream values and ensure correct handling in the factory.
    
    Suggested implementation:
    
    ```python
    import pytest
    
    @pytest.mark.parametrize(
        "streams",
        [
            None,
            [],
            ["stream1"],
            ["stream1", "stream2"],
        ]
    )
    def test_factory_streams_parametrized(factory, streams):
        result = factory.create(
            tap_class=factory.tap_class,
            config=factory.config,
            suite_config=None,
            streams=streams,
            parse_env_config=True,
        )
        # Add assertions here to verify correct handling of streams
        assert result is not None
        # Optionally, check that result.streams matches the input
        if hasattr(result, "streams"):
            assert result.streams == streams
    
    ```
    
    ```python
    # If there are other tests using streams, consider parametrizing them similarly.
    
    ```
    
    - You may need to adjust the test function name and the factory invocation to match your actual test and factory method signatures.
    - If your test suite uses fixtures for `factory`, ensure they are compatible with parametrization.
    - Add or refine assertions to check for correct behavior with each `streams` value.
    </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.

    @codecov
    Copy link

    codecov bot commented Sep 18, 2025

    Codecov Report

    ✅ All modified and coverable lines are covered by tests.
    ✅ Project coverage is 93.48%. Comparing base (ef953f5) to head (fca9043).

    Additional details and impacted files
    @@           Coverage Diff           @@
    ##             main    #3280   +/-   ##
    =======================================
      Coverage   93.47%   93.48%           
    =======================================
      Files          69       69           
      Lines        5659     5666    +7     
      Branches      699      700    +1     
    =======================================
    + Hits         5290     5297    +7     
      Misses        264      264           
      Partials      105      105           
    Flag Coverage Δ
    core 80.23% <50.00%> (-0.03%) ⬇️
    end-to-end 76.77% <80.00%> (-0.01%) ⬇️
    optional-components 43.31% <0.00%> (-0.06%) ⬇️

    Flags with carried forward coverage won't be shown. Click here to find out more.

    ☔ View full report in Codecov by Sentry.
    📢 Have feedback on the report? Share it here.

    🚀 New features to boost your workflow:
    • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

    @edgarrmondragon edgarrmondragon force-pushed the add-tests-for-taprunner-streams-parameter branch from 22c2bba to 41da3c6 Compare September 18, 2025 03:23
    @codspeed-hq
    Copy link

    codspeed-hq bot commented Sep 18, 2025

    CodSpeed Performance Report

    Merging #3280 will not alter performance

    Comparing add-tests-for-taprunner-streams-parameter (fca9043) with main (ef953f5)

    Summary

    ✅ 8 untouched

    @edgarrmondragon edgarrmondragon force-pushed the add-tests-for-taprunner-streams-parameter branch from 41da3c6 to e61f8a9 Compare September 18, 2025 03:25
    @edgarrmondragon edgarrmondragon force-pushed the add-tests-for-taprunner-streams-parameter branch from e61f8a9 to f57b9e6 Compare October 17, 2025 21:27
    - Add tests for TapTestRunner initialization with streams parameter
    - Add tests for run_sync_dry_run with streams parameter
    - Add tests for different stream sequence types (list, tuple, empty)
    - Add integration test for complete workflow with streams
    - Fix factory tests to include streams=None parameter expectations
    
    🤖 Generated with [Claude Code](https://claude.ai/code)
    
    Co-Authored-By: Claude <[email protected]>
    Signed-off-by: Edgar Ramírez Mondragón <[email protected]>
    @edgarrmondragon edgarrmondragon force-pushed the add-tests-for-taprunner-streams-parameter branch from f57b9e6 to fca9043 Compare October 17, 2025 23:23
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Labels

    None yet

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    2 participants