Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 11 additions & 19 deletions .github/workflows/sql-cli-test-and-build-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
python-version: [3.12]
opensearch-version: [ latest ]
# Note: OpenSearch version is determined by the SQL repository clone

steps:
- name: Checkout SQL CLI
Expand All @@ -30,26 +30,20 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Set up Java 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'

- name: Install Python Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
pip install setuptools wheel

# tests are designed to run against http://localhost:9200, so we have to disable/remove security plugin
- name: Download and run OpenSearch
run: |
docker run -p 9200:9200 -e "discovery.type=single-node" -e "DISABLE_SECURITY_PLUGIN=true" --name test -d opensearchproject/opensearch:${{ matrix.opensearch-version }}

- name: Wait for cluster to start
uses: nick-fields/retry@v2
with:
timeout_seconds: 1
max_attempts: 30
command: curl -q localhost:9200

- name: Run Tox Testing
run: tox
- name: Run Gradle Build and Tests
run: ./gradlew build

- name: Build Artifact
run: python setup.py sdist bdist_wheel
Expand All @@ -65,8 +59,6 @@ jobs:
name: opensearchsql
path: opensearchsql-builds

- name: Clean up container
- name: Clean up test cluster
if: always()
run: |
docker container stop test
docker container rm test
run: ./gradlew stopTestCluster
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,31 @@ For a list of all available configurations, see [config.yaml](src/main/python/op

The CLI supports all types of query that OpenSearch PPL/SQL supports. Refer to [OpenSearch SQL basic usage documentation.](https://github.com/opensearch-project/sql/blob/main/docs/user/dql/basics.rst)

## Development and Contributing

If you're interested in contributing to this project or running tests:

### Running Tests

The project includes an automated build and test system:

```bash
# Run all tests with automated cluster setup
./gradlew build
```

This command will:
- Build the Java and Python components
- Automatically clone/update the OpenSearch SQL repository to `./remote/sql`
- Start a test OpenSearch cluster in the background
- Load test data from `test_data/accounts.json`
- Run all Java and Python tests
- Clean up the test cluster automatically

For detailed development instructions, see:
- [Development Guide](development_guide.md) - Complete developer documentation
- [Contributing Guide](CONTRIBUTING.md) - How to contribute to the project
- [Test Suite Documentation](src/main/python/opensearchsql_cli/tests/README.md) - Testing details

## Code of Conduct

Expand Down
184 changes: 184 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,190 @@ test {
useJUnitPlatform()
}

// Python venv and pytest tasks
task setupVenv(type: Exec) {
description = 'Create Python virtual environment if it does not exist'
group = 'verification'

commandLine 'bash', '-c', '''
if [ ! -d "venv" ]; then
python3 -m venv venv
fi
'''
}

task installPythonDeps(type: Exec) {
description = 'Install Python dependencies in venv'
group = 'verification'
dependsOn setupVenv

commandLine 'bash', '-c', 'source venv/bin/activate && pip install -r requirements-dev.txt'
}

// Test cluster management tasks
task cloneOrPullSqlRepo(type: Exec) {
description = 'Clone or pull the SQL repository for testing'
group = 'verification'

commandLine 'bash', '-c', '''
if [ -d "remote/sql/.git" ]; then
echo "Pulling latest changes in remote/sql..."
cd remote/sql && git pull
else
echo "Cloning SQL repository..."
mkdir -p remote
git clone https://github.com/opensearch-project/sql.git remote/sql
fi
'''
}

task startTestCluster(type: Exec) {
description = 'Start OpenSearch test cluster in background (or detect existing)'
group = 'verification'
dependsOn cloneOrPullSqlRepo

commandLine 'bash', '-c', '''
set -e
mkdir -p build

# Check if cluster is already running
if curl -s http://localhost:9200 > /dev/null 2>&1; then
echo "Cluster already running at localhost:9200"
echo "Using existing cluster (will not stop it later)"
touch build/cluster.external
rm -f build/cluster.pid
exit 0
fi

# No cluster running, start our own
echo "No cluster detected, starting test cluster..."
rm -f build/cluster.external

cd remote/sql

# Stop any existing cluster we started previously
if [ -f "../../build/cluster.pid" ]; then
OLD_PID=$(cat ../../build/cluster.pid)
if ps -p $OLD_PID > /dev/null 2>&1; then
echo "Stopping previous cluster (PID: $OLD_PID)..."
kill $OLD_PID || true
sleep 5
fi
rm -f ../../build/cluster.pid
fi

# Start the cluster in background
nohup ./gradlew run > ../../build/cluster.log 2>&1 &
echo $! > ../../build/cluster.pid
echo "Cluster started with PID: $(cat ../../build/cluster.pid)"
'''
}

task waitForCluster(type: Exec) {
description = 'Wait for OpenSearch cluster to be ready'
group = 'verification'
dependsOn startTestCluster

commandLine 'bash', '-c', '''
# Quick check if cluster is already ready
if curl -s http://localhost:9200 > /dev/null 2>&1; then
echo "Cluster is ready!"
exit 0
fi

echo "Waiting for cluster to be ready..."
for i in {1..120}; do
if curl -s http://localhost:9200 > /dev/null 2>&1; then
echo "Cluster is ready!"
exit 0
fi
echo "Attempt $i/120: Cluster not ready yet, waiting..."
sleep 2
done
echo "Cluster failed to start within timeout"
exit 1
'''
}

task loadTestData(type: Exec) {
description = 'Load test data into OpenSearch cluster (idempotent)'
group = 'verification'
dependsOn waitForCluster

commandLine 'bash', '-c', '''
# Check if accounts index already exists with data
COUNT=$(curl -s "localhost:9200/accounts/_count" 2>/dev/null | grep -o '"count":[0-9]*' | grep -o '[0-9]*' || echo "0")

if [ "$COUNT" -gt "0" ]; then
echo "Test data already loaded (found $COUNT documents in accounts index)"
echo "Skipping data load"
exit 0
fi

echo "Loading test data..."
# Delete index if it exists but is empty
curl -s -X DELETE "localhost:9200/accounts" > /dev/null 2>&1 || true

# Load the data
curl -X POST "localhost:9200/accounts/_bulk" \
-H "Content-Type: application/x-ndjson" \
--data-binary @test_data/accounts.json
echo ""
echo "Test data loaded successfully"
'''
}

task pytest(type: Exec) {
description = 'Run pytest tests'
group = 'verification'
dependsOn installPythonDeps, loadTestData

workingDir = file('.')

commandLine 'bash', '-c', 'source venv/bin/activate && pytest src/main/python/opensearchsql_cli/tests/ -v'

// Fail the build if pytest fails
ignoreExitValue = false
}

task stopTestCluster(type: Exec) {
description = 'Stop the OpenSearch test cluster (only if we started it)'
group = 'verification'

commandLine 'bash', '-c', '''
# Don't stop external clusters
if [ -f "build/cluster.external" ]; then
echo "Cluster is external (not started by us), leaving it running"
rm -f build/cluster.external
exit 0
fi

# Stop cluster we started
if [ -f "build/cluster.pid" ]; then
PID=$(cat build/cluster.pid)
if ps -p $PID > /dev/null 2>&1; then
echo "Stopping cluster (PID: $PID)..."
kill $PID || true
sleep 2
# Force kill if still running
if ps -p $PID > /dev/null 2>&1; then
kill -9 $PID || true
fi
fi
rm -f build/cluster.pid
echo "Cluster stopped"
else
echo "No cluster to stop"
fi
'''
}

// Make test task depend on pytest (Python tests must pass for build to succeed)
test.dependsOn pytest

// Stop cluster after all tests complete (not just pytest)
test.finalizedBy stopTestCluster

spotless {
java {
target fileTree('.') {
Expand Down
Loading
Loading