Skip to content

Conversation

@kesmit13
Copy link
Collaborator

No description provided.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds automatic Docker container management for pytest tests, eliminating the need for manual container setup before running tests. The implementation introduces a conftest.py file with pytest hooks that automatically start a SingleStore Docker container if SINGLESTOREDB_URL is not set, and adds support for both MySQL protocol and HTTP Data API connections.

Key changes:

  • Automatic Docker container lifecycle management via pytest hooks
  • Support for using existing servers or auto-managed containers
  • HTTP Data API support with USE_DATA_API environment variable

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
singlestoredb/tests/conftest.py New file implementing pytest hooks for automatic container setup/teardown and environment protection fixtures
singlestoredb/pytest.py Enhanced _TestContainerManager to support existing servers, added HTTP URL property, fixed port mappings, and added output suppression for cleaner test output
singlestoredb/tests/utils.py Updated INIT_DB_URL logic to always use MySQL protocol for setup operations and added logging
singlestoredb/tests/test_plugin.py Added conditional test skipping for HTTP connections that don't support USE database commands
pyproject.toml Added docker package to test dependencies

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 206 to 208
env = {
'SINGLESTORE_LICENSE': license,
}
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

The start() method attempts to access os.environ['SINGLESTORE_LICENSE'] directly, which will raise a KeyError if the environment variable is not set. This contradicts the earlier logic in __init__ (lines 117-121) where the code uses .get() with a fallback to an empty string.

The code should use os.environ.get('SINGLESTORE_LICENSE', '') instead to be consistent with the initialization logic and avoid a KeyError when the license is not set.

Copilot uses AI. Check for mistakes.
)
except Exception as e:
logger.exception(e)
raise RuntimeError('Failed to stop container.') from e
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

The error message "Failed to stop container." is misleading because this exception handler is for the docker rm command, not the docker stop command. The message should be "Failed to remove container." to accurately reflect the operation that failed.

Suggested change
raise RuntimeError('Failed to stop container.') from e
raise RuntimeError('Failed to remove container.') from e

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +91
if not _container_manager.use_existing:
_container_manager.start()
print(f'Container {_container_manager.container_name} started')
print('Waiting for SingleStoreDB to be ready...')

# Wait for container to be ready
try:
conn = _container_manager.connect()
conn.close()
print('✓ SingleStoreDB is ready!')
logger.info('Docker container is ready')
except Exception as e:
print(f'✗ Failed to connect to Docker container: {e}')
logger.error(f'Failed to connect to Docker container: {e}')
raise

Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

[nitpick] The condition if not _container_manager.use_existing: on line 76 is redundant. Since line 66 already checks that SINGLESTOREDB_URL is not in the environment, and _TestContainerManager.__init__() sets use_existing based on the presence of SINGLESTOREDB_URL, the use_existing flag will always be False at this point.

This check could be removed to simplify the logic, or the outer condition on line 66 could be removed to allow the _TestContainerManager to handle the logic internally. The current structure is confusing and adds unnecessary nesting.

Suggested change
if not _container_manager.use_existing:
_container_manager.start()
print(f'Container {_container_manager.container_name} started')
print('Waiting for SingleStoreDB to be ready...')
# Wait for container to be ready
try:
conn = _container_manager.connect()
conn.close()
print('✓ SingleStoreDB is ready!')
logger.info('Docker container is ready')
except Exception as e:
print(f'✗ Failed to connect to Docker container: {e}')
logger.error(f'Failed to connect to Docker container: {e}')
raise
_container_manager.start()
print(f'Container {_container_manager.container_name} started')
print('Waiting for SingleStoreDB to be ready...')
# Wait for container to be ready
try:
conn = _container_manager.connect()
conn.close()
print('✓ SingleStoreDB is ready!')
logger.info('Docker container is ready')
except Exception as e:
print(f'✗ Failed to connect to Docker container: {e}')
logger.error(f'Failed to connect to Docker container: {e}')
raise

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +121
# Use SINGLESTORE_LICENSE from environment, or empty string as fallback
# Empty string works for the client SDK
license = os.environ.get('SINGLESTORE_LICENSE', '')
if not license:
logger.info('SINGLESTORE_LICENSE not set, using empty string')
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

The license variable retrieved on line 119 is never actually used. Line 125 sets 'SINGLESTORE_LICENSE': None in the environment_vars dictionary, ignoring the license value that was just retrieved. This appears to be a bug.

If the intent is to use the retrieved license value, the code should be:

'SINGLESTORE_LICENSE': None if not license else license,

or simply remove the license retrieval code if it's not meant to be used here (since it's set separately in the start() method's env parameter).

Copilot uses AI. Check for mistakes.
Comment on lines 19 to 20
'http://' in os.environ.get('SINGLESTOREDB_URL', '') or
'https://' in os.environ.get('SINGLESTOREDB_URL', ''),
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

The skip condition checks for 'http://' or 'https://' in the URL, but the actual HTTP URL format used in conftest.py (line 149 of pytest.py) is singlestoredb+http://, not http://. This means the skip condition will fail to skip these tests when using the HTTP Data API, which could cause test failures.

The condition should be updated to:

pytestmark = pytest.mark.skipif(
    'http' in os.environ.get('SINGLESTOREDB_URL', ''),
    reason='Plugin tests require MySQL protocol (USE database not supported via HTTP)',
)

or more precisely:

pytestmark = pytest.mark.skipif(
    any(x in os.environ.get('SINGLESTOREDB_URL', '') for x in ['http://', 'https://', '+http://', '+https://']),
    reason='Plugin tests require MySQL protocol (USE database not supported via HTTP)',
)
Suggested change
'http://' in os.environ.get('SINGLESTOREDB_URL', '') or
'https://' in os.environ.get('SINGLESTOREDB_URL', ''),
any(x in os.environ.get('SINGLESTOREDB_URL', '') for x in ['http://', 'https://', '+http://', '+https://']),

Copilot uses AI. Check for mistakes.
from collections.abc import Iterator
from typing import Optional

import pytest
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

Module 'pytest' is imported with both 'import' and 'import from'.
Module 'singlestoredb.pytest' is imported with both 'import' and 'import from'.

Copilot uses AI. Check for mistakes.

from singlestoredb.pytest import _TestContainerManager
from singlestoredb.pytest import execution_mode # noqa: F401
from singlestoredb.pytest import ExecutionMode # noqa: F401
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

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

Import of 'ExecutionMode' is not used.

Suggested change
from singlestoredb.pytest import ExecutionMode # noqa: F401

Copilot uses AI. Check for mistakes.
kesmit13 and others added 2 commits November 14, 2025 13:35
This commit enables running tests via HTTP Data API when USE_DATA_API=1
is set, while setup operations still use MySQL protocol for commands that
aren't supported over HTTP.

Changes:
- singlestoredb/pytest.py: Added http_connection_url property, fixed port
  mapping (9000 for Data API, 8080 for Studio), suppressed Docker
  container ID output
- singlestoredb/tests/conftest.py: Added USE_DATA_API environment variable
  support, sets SINGLESTOREDB_INIT_DB_URL for setup operations, added
  clear logging for Docker lifecycle and connection mode
- singlestoredb/tests/utils.py: Modified load_sql to always use
  SINGLESTOREDB_INIT_DB_URL when set for setup operations like SET GLOBAL
- singlestoredb/tests/test_plugin.py: Added skip marker for HTTP Data API
  mode since USE database doesn't work over HTTP
- pyproject.toml: Added docker to test dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@kesmit13 kesmit13 merged commit ea9af55 into main Nov 17, 2025
11 checks passed
@kesmit13 kesmit13 deleted the docker-all-tests branch November 17, 2025 15:18
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