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
41 changes: 41 additions & 0 deletions .github/workflows/cli-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: CLI Tests

on:
pull_request:
branches: [main]

jobs:
test:
name: Test CLI on ${{ matrix.python-version }}
runs-on: ubuntu-latest

strategy:
matrix:
# Test 3.9 for T7, 3.12 for general/cloud use
python-version: ["3.9", "3.12"]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry
uses: abatilo/actions-poetry@v4

- name: Configure Poetry to use in-project virtualenv
run: poetry config virtualenvs.in-project true

- name: Install dependencies (including dev/test) and project
run: poetry install --with dev --no-interaction

- name: Smoke-test CLI on Python 3.9
if: matrix.python-version == '3.9'
run: poetry run python scripts/smoke_test_cli.py

- name: Run full test suite (Python >= 3.10)
if: matrix.python-version != '3.9'
run: poetry run pytest -q
39 changes: 30 additions & 9 deletions cwmscli/commands/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
import sys
from typing import Optional, Sequence

import cwms
import pandas as pd
import requests

from cwmscli.utils import get_api_key
from cwmscli.utils.deps import requires

Expand Down Expand Up @@ -90,6 +86,9 @@ def _save_base64(


def store_blob(**kwargs):
import cwms
import requests

file_data = kwargs.get("file_data")
blob_id = kwargs.get("blob_id", "").upper()
# Attempt to determine what media type should be used for the mime-type if one is not presented based on the file extension
Expand Down Expand Up @@ -145,6 +144,9 @@ def store_blob(**kwargs):


def retrieve_blob(**kwargs):
import cwms
import requests

blob_id = kwargs.get("blob_id", "").upper()
if not blob_id:
logging.warning(
Expand Down Expand Up @@ -172,14 +174,17 @@ def retrieve_blob(**kwargs):


def delete_blob(**kwargs):
import cwms
import requests

blob_id = kwargs.get("blob_id").upper()
logging.debug(f"Office: {kwargs.get('office')} Blob ID: {blob_id}")

try:
# cwms.delete_blob(
# office_id=kwargs.get("office"),
# blob_id=kwargs.get("blob_id").upper(),
# )
cwms.delete_blob(
office_id=kwargs.get("office"),
blob_id=kwargs.get("blob_id").upper(),
)
logging.info(f"Successfully deleted blob with ID: {blob_id}")
except requests.HTTPError as e:
details = getattr(e.response, "text", "") or str(e)
Expand All @@ -197,8 +202,11 @@ def list_blobs(
sort_by: Optional[Sequence[str]] = None,
ascending: bool = True,
limit: Optional[int] = None,
) -> pd.DataFrame:
):
logging.info(f"Listing blobs for office: {office!r}...")
import cwms
import pandas as pd

result = cwms.get_blobs(office_id=office, blob_id_like=blob_id_like)

# Accept either a DataFrame or a JSON/dict-like response
Expand Down Expand Up @@ -250,6 +258,9 @@ def upload_cmd(
api_root: str,
api_key: str,
):
import cwms
import requests

cwms.init_session(api_root=api_root, api_key=get_api_key(api_key, ""))
try:
file_size = os.path.getsize(input_file)
Expand Down Expand Up @@ -307,6 +318,9 @@ def upload_cmd(
def download_cmd(
blob_id: str, dest: str, office: str, api_root: str, api_key: str, dry_run: bool
):
import cwms
import requests

if dry_run:
logging.info(
f"DRY RUN: would GET {api_root} blob with blob-id={blob_id} office={office}."
Expand All @@ -331,6 +345,8 @@ def download_cmd(


def delete_cmd(blob_id: str, office: str, api_root: str, api_key: str, dry_run: bool):
import cwms

if dry_run:
logging.info(
f"DRY RUN: would DELETE {api_root} blob with blob-id={blob_id} office={office}"
Expand All @@ -352,6 +368,8 @@ def update_cmd(
api_root: str,
api_key: str,
):
import cwms

if dry_run:
logging.info(
f"DRY RUN: would PATCH {api_root} blob with blob-id={blob_id} office={office}"
Expand Down Expand Up @@ -398,6 +416,9 @@ def list_cmd(
api_root: str,
api_key: str,
):
import cwms
import pandas as pd

cwms.init_session(api_root=api_root, api_key=get_api_key(api_key, None))
df = list_blobs(
office=office,
Expand Down
6 changes: 5 additions & 1 deletion cwmscli/commands/commands_cwms.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ def csv2cwms_cmd(**kwargs):
"""
),
)
@requires(reqs.cwms)
def blob_group():
pass

Expand Down Expand Up @@ -137,6 +136,7 @@ def blob_group():
)
@click.option("--dry-run", is_flag=True, help="Show request; do not send.")
@common_api_options
@requires(reqs.cwms)
def blob_upload(**kwargs):
from cwmscli.commands.blob import upload_cmd

Expand All @@ -156,6 +156,7 @@ def blob_upload(**kwargs):
)
@click.option("--dry-run", is_flag=True, help="Show request; do not send.")
@common_api_options
@requires(reqs.cwms)
def blob_download(**kwargs):
from cwmscli.commands.blob import download_cmd

Expand All @@ -169,6 +170,7 @@ def blob_download(**kwargs):
@click.option("--blob-id", required=True, type=str, help="Blob ID to delete.")
@click.option("--dry-run", is_flag=True, help="Show request; do not send.")
@common_api_options
@requires(reqs.cwms)
def delete_cmd(**kwargs):
from cwmscli.commands.blob import delete_cmd

Expand Down Expand Up @@ -204,6 +206,7 @@ def delete_cmd(**kwargs):
help="If true, replace existing blob.",
)
@common_api_options
@requires(reqs.cwms)
def update_cmd(**kwargs):
from cwmscli.commands.blob import update_cmd

Expand Down Expand Up @@ -243,6 +246,7 @@ def update_cmd(**kwargs):
help="If set, write results to this CSV file.",
)
@common_api_options
@requires(reqs.cwms)
def list_cmd(**kwargs):
from cwmscli.commands.blob import list_cmd

Expand Down
76 changes: 75 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ black = "^24.2.0"
isort = "^5.13.2"
mypy = "^1.9.0"
pre-commit = "^3.6.2"
#pytest = "^8.1.1"
pytest = { version = "^9.0.2", python = ">=3.10" }
#pytest-cov = "^4.1.0"
#pandas-stubs = "^2.2.1.240316"
yamlfix = "^1.16.0"
Expand Down
10 changes: 10 additions & 0 deletions scripts/smoke_test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Used to ensure cli will run under Python 3.9

from click.testing import CliRunner

from cwmscli.__main__ import cli

runner = CliRunner()
result = runner.invoke(cli, ["--help"])
assert result.exit_code == 0, "CLI failed to run under Python 3.9"
print("CLI loads and runs under Python 3.9")
18 changes: 18 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Testing

Tests located here will invoke the CliRunner that `click` provides.

https://click.palletsprojects.com/en/stable/testing/

These tests are more for testing the runner itself and ensuring input/output does not change unexpectedly.

Further testing exists within the individual scripts to test the functionality of those scripts regardless of the `click` integrations and/or API targets.

## Goals

- Assign extensive tests per root `cli` command:
- Should have each of the sub commands covered
- Tests each argument
- Have comparisons for expected output both file and stdout
- Maintain tests as new features are added
- Ensure PR blocking to main in the event a given test fails
Loading