Skip to content

Commit d33bda6

Browse files
Merge pull request #327 from nasa/feature/issue-326-programmatically-download-test-files-for-comparisons
Programmatically download IceSAT-2 test files instead of git lfs
2 parents b89bb05 + 3e0e629 commit d33bda6

9 files changed

Lines changed: 1273 additions & 98 deletions

File tree

.github/workflows/build-pipeline.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ on:
1111

1212
env:
1313
POETRY_VERSION: "2.1.3"
14-
PYTHON_VERSION: "3.10"
14+
PYTHON_VERSION: "3.11"
1515

1616
jobs:
1717
run_tests:
1818
uses: ./.github/workflows/reusable_run_tests.yml
1919
secrets:
2020
codecov_token: ${{ secrets.CODECOV_TOKEN }}
21+
EARTHDATA_USERNAME: ${{ secrets.EARTHDATA_USERNAME }}
22+
EARTHDATA_PASSWORD: ${{ secrets.EARTHDATA_PASSWORD }}
2123

2224
bump_version:
2325
needs: run_tests

.github/workflows/release_created.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
env:
88
POETRY_VERSION: "2.1.3"
9-
PYTHON_VERSION: "3.10"
9+
PYTHON_VERSION: "3.11"
1010

1111
jobs:
1212
# First job in the workflow builds and verifies the software artifacts

.github/workflows/reusable_run_tests.yml

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ on:
1010
secrets:
1111
codecov_token:
1212
required: true
13+
EARTHDATA_USERNAME:
14+
description: 'NASA Earthdata username'
15+
required: true
16+
EARTHDATA_PASSWORD:
17+
description: 'NASA Earthdata password'
18+
required: true
1319
workflow_dispatch:
1420

1521
env:
@@ -20,13 +26,11 @@ jobs:
2026
runs-on: ubuntu-latest
2127
strategy:
2228
matrix:
23-
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
29+
python-version: [ '3.11', '3.12', '3.13', '3.14' ]
2430

2531
name: Python ${{ matrix.python-version }} tests
2632
steps:
2733
- uses: actions/checkout@v5
28-
with:
29-
lfs: 'true'
3034

3135
- name: Set up Python
3236
uses: actions/setup-python@v5
@@ -45,12 +49,27 @@ jobs:
4549
run: |
4650
poetry run ruff check ncompare
4751
48-
- name: Run tests with coverage
52+
- name: Run unit tests with coverage
53+
run: |
54+
poetry run pytest -v -m "not integration" --cov=ncompare --cov-report=
55+
56+
- name: Run integration tests with coverage
57+
env:
58+
EARTHDATA_USERNAME: ${{ secrets.EARTHDATA_USERNAME }}
59+
EARTHDATA_PASSWORD: ${{ secrets.EARTHDATA_PASSWORD }}
60+
run: |
61+
poetry run pytest -v -m integration --cov=ncompare --cov-append --cov-report=
62+
63+
- name: Generate combined coverage report
4964
run: |
50-
poetry run pytest --cov=ncompare --cov-report=xml:build/reports/coverage${{ matrix.python-version }}.xml
65+
poetry run coverage xml -o build/reports/coverage${{ matrix.python-version }}.xml
66+
poetry run coverage report
5167
5268
- name: Upload coverage reports to Codecov
5369
uses: codecov/codecov-action@v5
5470
with:
5571
token: ${{ secrets.CODECOV_TOKEN }}
72+
files: build/reports/coverage${{ matrix.python-version }}.xml
73+
flags: python-${{ matrix.python-version }}
74+
name: python-${{ matrix.python-version }}
5675
verbose: true

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ ci:
55
autofix_prs: false # Comment "pre-commit.ci autofix" on a PR to trigger
66

77
default_language_version:
8-
python: python3.10
8+
python: python3.11
99

1010
repos:
1111
- repo: https://github.com/gitleaks/gitleaks
12-
rev: v8.28.0
12+
rev: v8.30.0
1313
hooks:
1414
- id: gitleaks
1515

@@ -41,14 +41,14 @@ repos:
4141
exclude_types: ["jupyter", "text"]
4242

4343
- repo: https://github.com/astral-sh/ruff-pre-commit
44-
rev: v0.13.3
44+
rev: v0.14.10
4545
hooks:
4646
- id: ruff
4747
args: ["--fix", "--exit-non-zero-on-fix"]
4848
- id: ruff-format
4949

5050
- repo: https://github.com/pre-commit/mirrors-mypy
51-
rev: v1.18.2
51+
rev: v1.19.1
5252
hooks:
5353
- id: mypy
5454

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
### Changed
1010

1111
- update the default python version from 3.9 to 3.10 ([#323](https://github.com/nasa/stitchee/pull/323))([**@danielfromearth**](https://github.com/danielfromearth))
12+
- Download ICESat-2 ATL06 granules for integration testing instead of using git lfs ([#327](https://github.com/nasa/stitchee/pull/327))([**@danielfromearth**](https://github.com/danielfromearth))
1213

1314
## [1.13.1] - 2025-01-08
1415

poetry.lock

Lines changed: 1134 additions & 81 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,26 @@ classifiers = [
1212
"Operating System :: Microsoft :: Windows",
1313
"Operating System :: MacOS",
1414
"Operating System :: POSIX :: Linux",
15-
"Programming Language :: Python :: 3.10",
1615
"Programming Language :: Python :: 3.11",
1716
"Programming Language :: Python :: 3.12",
1817
"Programming Language :: Python :: 3.13",
18+
"Programming Language :: Python :: 3.14",
1919
"Topic :: Software Development :: Libraries :: Python Modules",
2020
]
2121

2222
[tool.poetry.scripts]
2323
ncompare = "ncompare.console:main"
2424

2525
[tool.poetry.dependencies]
26-
python = "^3.10"
26+
python = "^3.11"
2727
numpy = ">=1.26.0"
2828
netCDF4 = ">=1.6.4"
2929
xarray = ">=2023.9"
3030
colorama = ">=0.4.6"
3131
openpyxl = ">=3.1.2"
3232
h5py = ">=3.12.1"
3333
h5netcdf = ">=1.4.1"
34+
earthaccess = ">=0.15.1"
3435

3536
[tool.poetry.group.dev.dependencies]
3637
pytest = ">=7.4.2,<9.0.0"
@@ -48,6 +49,15 @@ mkdocs-material = ">=9.5.12"
4849
requires = ["poetry-core>=1.0.0"]
4950
build-backend = "poetry.core.masonry.api"
5051

52+
[tool.pytest.ini_options]
53+
markers = [
54+
"integration: marks tests as integration tests (downloads data, requires auth)",
55+
"slow: marks tests as slow running",
56+
]
57+
# Skip integration tests by default
58+
addopts = "-v -m 'not integration'"
59+
testpaths = ["tests"]
60+
5161
[[tool.mypy.overrides]]
5262
module = [
5363
"colorama.*",
@@ -66,7 +76,7 @@ exclude = [
6676
]
6777
# Allow lines to be as long as 100.
6878
line-length = 100
69-
target-version = "py310"
79+
target-version = "py311"
7080

7181
[tool.ruff.lint]
7282
# E402: module level import not at top of file

tests/conftest.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2424
# See the License for the specific language governing permissions and limitations under the License.
2525

26+
import os
2627
from pathlib import Path
2728

29+
import earthaccess
2830
import netCDF4 as nC
2931
import numpy as np
3032
import pytest
@@ -33,6 +35,89 @@
3335
from ncompare.printing import Outputter
3436

3537

38+
@pytest.fixture(scope="session")
39+
def icesat2_cache_dir():
40+
"""Persistent cache directory for ICESat-2 test data."""
41+
cache_dir = Path.home() / ".cache" / "icesat2_test_data"
42+
cache_dir.mkdir(parents=True, exist_ok=True)
43+
return cache_dir
44+
45+
46+
@pytest.fixture(scope="session")
47+
def earthdata_auth():
48+
"""
49+
Authenticate with NASA Earthdata.
50+
Uses credentials from environment variables or .netrc file.
51+
"""
52+
# Check for environment variables (used in CI)
53+
username = os.getenv("EARTHDATA_USERNAME")
54+
password = os.getenv("EARTHDATA_PASSWORD")
55+
56+
if username and password:
57+
earthaccess.login(strategy="environment")
58+
else:
59+
# Use .netrc or prompt for local testing
60+
earthaccess.login()
61+
62+
return True
63+
64+
65+
@pytest.fixture(scope="session")
66+
def icesat2_atl06_granule_1(icesat2_cache_dir, earthdata_auth):
67+
"""
68+
Download or use cached ICESat-2 ATL06 granule #1 for comparison tests.
69+
Temporal range: 2023-08-16 16:16:15 to 2023-08-16 16:25:00
70+
"""
71+
# Check if already cached
72+
cached_files = list(icesat2_cache_dir.glob("ATL06_20230816161508_*.h5"))
73+
if cached_files:
74+
return str(cached_files[0])
75+
76+
# Download if not cached
77+
results = earthaccess.search_data(
78+
short_name="ATL06", temporal=("2023-08-16 16:16:15", "2023-08-16 16:25:00"), count=1
79+
)
80+
81+
if not results:
82+
pytest.skip("ICESat-2 granule #1 not found for test")
83+
84+
# Download the data
85+
files = earthaccess.download(results, str(icesat2_cache_dir))
86+
87+
if not files:
88+
pytest.skip("Failed to download ICESat-2 granule #1")
89+
90+
return files[0]
91+
92+
93+
@pytest.fixture(scope="session")
94+
def icesat2_atl06_granule_2(icesat2_cache_dir, earthdata_auth):
95+
"""
96+
Download or use cached ICESat-2 ATL06 granule #2 for comparison tests.
97+
Temporal range: 2023-08-16 23:46:00 to 2023-08-16 23:48:00
98+
"""
99+
# Check if already cached
100+
cached_files = list(icesat2_cache_dir.glob("ATL06_20230816234629_*.h5"))
101+
if cached_files:
102+
return str(cached_files[0])
103+
104+
# Download if not cached
105+
results = earthaccess.search_data(
106+
short_name="ATL06", temporal=("2023-08-16 23:46:00", "2023-08-16 23:48:00"), count=1
107+
)
108+
109+
if not results:
110+
pytest.skip("ICESat-2 granule #2 not found for test")
111+
112+
# Download the data
113+
files = earthaccess.download(results, str(icesat2_cache_dir))
114+
115+
if not files:
116+
pytest.skip("Failed to download ICESat-2 granule #2")
117+
118+
return files[0]
119+
120+
36121
@pytest.fixture(scope="session")
37122
def temp_data_dir(tmpdir_factory) -> Path:
38123
return Path(tmpdir_factory.mktemp("data"))

tests/test_core.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,23 @@ def test_zero_for_comparison_with_no_differences(ds_3dims_3vars_4coords_1subgrou
7474
assert compare(ds_3dims_3vars_4coords_1subgroup, ds_3dims_3vars_4coords_1subgroup) == 0
7575

7676

77-
def test_icesat(temp_data_dir):
77+
@pytest.mark.integration
78+
def test_icesat(temp_data_dir, icesat2_atl06_granule_1, icesat2_atl06_granule_2):
7879
# Compare the `ncompare` output when testing ICESat
7980
out_path = temp_data_dir / "output_file_icesat-2-atl06.txt"
8081

8182
num_differences = compare(
82-
data_for_tests_dir / "icesat-2-ATL06" / "ATL06_20230816161508_08782002_006_02.h5",
83-
data_for_tests_dir / "icesat-2-ATL06" / "ATL06_20230816234629_08822013_006_01.h5",
83+
icesat2_atl06_granule_1,
84+
icesat2_atl06_granule_2,
8485
show_chunks=True,
8586
show_attributes=True,
8687
file_text=str(out_path),
8788
)
8889

90+
# Verify that differences were found and output was written
91+
assert num_differences > 0, "Expected to find differences between granules"
92+
assert out_path.exists(), "Output file was not created"
93+
8994
assert num_differences == 5280
9095

9196

0 commit comments

Comments
 (0)