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
5 changes: 4 additions & 1 deletion .github/workflows/build_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ jobs:
run: |
python -m pip install .

# Run machine-independent tests
- name: Run Tests
run: |
python -m unittest tests/test_*.py
pytest tests/unit/test_*.py
python -m unittest tests/integration/python_tests/group_by_command/test_*.py
python -m unittest tests/integration/python_tests/group_by_workflow/test_*.py

# Build documentation on all PRs and pushes; only publish (commit to gh-pages) on pushes.
build-docs:
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
build/
dist/
tests/test_follow_symlinks/
tests/test_follow_symlinks_non_archived/
tests/utils/test_follow_symlinks
tests/utils/test_follow_symlinks_non_archived
zstash.egg-info/
*.pyc
*~
Expand Down
6 changes: 5 additions & 1 deletion conda/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dependencies:
- python >=3.11,<3.14
- sqlite
- six >=1.16.0
- globus-sdk >=3.15.0
- globus-sdk >=3.15.0,<4.0
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Without this, we get AttributeError: 'TransferClient' object has no attribute 'endpoint_autoactivate'

# Developer Tools
# =================
# If versions are updated, also update 'rev' in `.pre-commit.config.yaml`
Expand All @@ -18,6 +18,10 @@ dependencies:
- mypy ==1.18.2
- pre-commit ==4.3.0
- tbump >=6.9.0
# Testing
# =======================
- pytest
- pytest-cov
# Documentation
# =================
# If versions are updated, also update in `.github/workflows/workflow.yml`
Expand Down
120 changes: 120 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# zstash Test Suite

## The test directory structure

```
tests/
integration/ # Tests that call zstash from the command line
bash_tests/ # Test zstash commands via bash scripts
run_from_chrysalis/ # Run these from Chrysalis (these use Globus and/or require the Chrysalis file system)
run_from_perlmutter/ # Run these from Perlmutter (these use `hsi` directly and/or require the Perlmutter file system)
python_tests/ # Test zstash commands via Python unittest wrappers
group_by_command # Tests organized by command
group_by_workflow # Tests organized by workflow
unit/ # Tests of pure functions (uses pytest, not unittest)
utils/ # Utilities for testing
```

## Testing example for Perlmutter

```bash
rm -rf build
conda clean --all --y
conda env create -f conda/dev.yml -n zstash_dev_20251017_test1
conda activate zstash_dev_20251017_test1
pre-commit run --all-files
python -m pip install .
pytest tests/unit/test_*.py
# 1 passed in 0.19s
python -m unittest tests/integration/python_tests/group_by_command/test_*.py
# Ran 69 tests in 327.570s
# OK
python -m unittest tests/integration/python_tests/group_by_workflow/test_*.py
# Ran 4 tests in 2.666s
# OK
cd tests/integration/bash_tests/run_from_perlmutter/
time ./follow_symlinks.sh # NOTE: you will have to change out paths for your username
# real 0m31.851s
# No errors
time ./test_update_non_empty_hpss.bash
# real 0m10.062s
# No errors

# Log into globus.org
# Log into endpoints (NERSC Perlmutter, Globus Tutorial Collection 1) at globus.org: File Manager > Add the endpoints in the "Collection" fields
time ./test_ls_globus.bash
# real 0m26.930s
# No errors
```

## Testing example for Chrysalis

```bash
rm -rf build
conda clean --all --y
conda env create -f conda/dev.yml -n zstash_dev_20251017_test1
conda activate zstash_dev_20251017_test1
pre-commit run --all-files
python -m pip install .
pytest tests/unit/test_*.py
# 1 passed in 0.84s
python -m unittest tests/integration/python_tests/group_by_command/test_*.py
# Ran 69 tests in 110.139s
# OK (skipped=32)
# NOTE: Some tests are skipped because Chrysalis doesn't have direct `hsi`/HPSS access
python -m unittest tests/integration/python_tests/group_by_workflow/test_*.py
# Ran 4 tests in 6.889s
# OK
cd tests/integration/bash_tests/run_from_chrysalis/

# Log into globus.org
# 1. Log into endpoints (LCRC Improv DTN, NERSC Perlmutter) at globus.org: File Manager > Add the endpoints in the "Collection" fields
# 2. To start fresh, with no consents: https://auth.globus.org/v2/web/consents > Manage Your Consents > Globus Endpoint Performance Monitoring > rescind all"
# Then, increment `try_num` below to avoid using an old directory.
# Alternatively, start fresh by deleting the directory on Perlmutter:
# `rm -rf /global/homes/f/forsyth/zstash/tests/test_globus_auth_try{try_num}`
time ./globus_auth.bash try_num # NOTE: you will have to change out paths for your username
# Paste the URL into your browser
# Log into Argonne
# Log into NERSC
# Provide a label
# Copy the auth code to the command line
#
# real 2m45.954s
# No errors

# If not done above, do the following:
# Log into globus.org
# Log into endpoints (LCRC Improv DTN, NERSC Perlmutter) at globus.org: File Manager > Add the endpoints in the "Collection" fields

# In all cases, do:
# Then, increment `try_num` below to avoid using an old directory.
# Alternatively, start fresh by deleting the directory on Perlmutter:
# `rm -rf /global/homes/f/forsyth/zstash/tests/test_database_corruption_try{try_num}`
time ./database_corruption.bash try_num # NOTE: you will have to change out paths for your username
# Success count: 25
# Fail count: 0
# real 6m43.994s

time ./symlinks.sh # NOTE: you will have to change out paths for your username
# real 0m1.346s
# No errors

cd blocking_test_scripts
# Review README_TEST_BLOCKING
# This uses "12 piControl ocean monthly files, 49 GB",
# so processing may take a long time.
# TODO (later PR): Confirm this test works
```

## Testing with GitHub Actions

GitHub Actions runs the tests according to `.github/workflows/build_workflow.yml`:
```
# Run machine-independent tests
- name: Run Tests
run: |
pytest tests/unit/test_*.py
python -m unittest tests/integration/python_tests/group_by_command/test_*.py
python -m unittest tests/integration/python_tests/group_by_workflow/test_*.py
```
Empty file added tests/integration/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,7 @@ II. Running the Test Script

The test script "test_zstash_blocking.sh" accepts two positional parameters:

test_zstash_blocking.sh (BLOCKING|NON_BLOCKING) [NEW_CREDS]

On an initial run, or whenever Globus complains of authentication failures,
add "NEW_CREDS" as the second parameter. This will act to delete your
cached Globus credentials and trigger prompts for you to paste login URLs
to your browser (generally one per endpoint) which requires that you conduct
a login sequence, and then paste a returned key-value at the bash command
prompt. After both keys are accepted, you can re-run the test script
without "NEW_CREDS", until the credentials expire (usually 24 hours.)
test_zstash_blocking.sh (BLOCKING|NON_BLOCKING)

If "BLOCKING" is selected, zstash will run in default mode, waiting for
each tar file to complete transfer before generating another tar file.
Expand All @@ -93,7 +85,7 @@ so that your command prompt returns and you can monitor progress with
snapshot.sh

which will provide a view of both the tarfile cache and the destination
directory for delivred tar files. It is also suggested that you name your
directory for delivered tar files. It is also suggested that you name your
logfile to reflect the date, and whether BLOCKING or not was specified.


Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#!/bin/bash

if [[ $# -lt 1 ]]; then
echo "Usage: text_zstash_blocking.sh (BLOCKING|NON_BLOCKING) [NEW_CREDS]"
echo "Usage: text_zstash_blocking.sh (BLOCKING|NON_BLOCKING)"
echo " One of \"BLOCKING\" or \"NON_BLOCKING\" must be supplied as the"
echo " first parameter."
echo " Add \"NEW_CREDS\" if Globus credentials have expired."
echo " This will cause Globus to prompt for new credentials."
exit 0
fi

Expand All @@ -20,14 +18,6 @@ else
exit 0
fi

# remove old auth data, if exists, so that globus will prompt us
# for new auth credentials in case they have expired:
if [[ $# -gt 1 ]]; then
if [[ $2 == "NEW_CREDS" ]]: then
rm -f ~/.globus-native-apps.cfg
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This file is no longer used, as of #380.

fi
fi


base_dir=`pwd`
base_dir=`realpath $base_dir`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,13 @@ setup()

run_test_cases()
{
# Before running the first time:
# globus.org
# Authenticate into LCRC Improv DTN, NERSC Perlmutter
# Run toy problem:
#
# source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh
# cd /lcrc/group/e3sm/ac.forsyth2/zstash_testing/test_20250729
# mkdir zstash_demo; echo 'file0 stuff' > zstash_demo/file0.txt
# Chrysalis: 15288284-7006-4041-ba1a-6b52501e49f1
# Perlmutter: 6bdc7956-fc0f-4ad2-989c-7aa5ee643a79
# zstash create --hpss=globus://6bdc7956-fc0f-4ad2-989c-7aa5ee643a79/global/homes/f/forsyth/zstash/tests/manual_run zstash_demo
# Will prompt for LCRC AND NERSC authentication, and then paste generated auth code one time.

# Before each run:
# Perlmutter:
# cd /global/homes/f/forsyth/zstash/tests/
# rm -rf test_database_corruption
#
# Chrysalis:
# cd ~/ez/zstash/
# conda activate zstash-377-20250728
# pre-commit run --all-files
# python -m pip install .
# cd tests/scripts
# ./database_corruption.bash
local try_num=$1

SRC_DIR=/lcrc/group/e3sm/ac.forsyth2/zstash_testing/test_database_corruption # Chrysalis
DST_DIR=globus://6bdc7956-fc0f-4ad2-989c-7aa5ee643a79/global/homes/f/forsyth/zstash/tests/test_database_corruption # Perlmutter
DST_DIR=globus://6bdc7956-fc0f-4ad2-989c-7aa5ee643a79/global/homes/f/forsyth/zstash/tests/test_database_corruption_try${try_num} # Perlmutter
# To start fresh with try_num=1, delete the above directory on Perlmutter before running. Example:
# rm -rf /global/homes/f/forsyth/zstash/tests/test_database_corruption_try1

success_count=0
fail_count=0
Expand Down Expand Up @@ -318,7 +297,7 @@ run_test_cases()
echo "Review: ${review_str}"
}

run_test_cases
run_test_cases "$1"

# Success count: 25
# Fail count: 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ check_log_has()
{
local expected_grep="${1}"
local log_file="${2}"
grep "${expected_grep}" ${log_file}
grep -q "${expected_grep}" ${log_file}
if [ $? != 0 ]; then
echo "Expected grep '${expected_grep}' not found in ${log_file}. Test failed."
exit 2
Expand All @@ -40,30 +40,14 @@ check_log_does_not_have()

run_test_cases()
{
# This script requires user input and thus cannot be run automatically as part of a test suite.

# To start fresh with Globus:
# 1. Log into endpoints (LCRC Improv DTN, NERSC Perlmutter) at globus.org: File Manager > Add the endpoints in the "Collection" fields
# 2. To start fresh, with no consents: https://auth.globus.org/v2/web/consents > Manage Your Consents > Globus Endpoint Performance Monitoring > rescind all"

# Before each run:
# Perlmutter:
# cd /global/homes/f/forsyth/zstash/tests/
# rm -rf test_globus_auth_try1 # Or just change $DST_DIR to a new directory
#
# Chrysalis:
# cd ~/ez/zstash/
# conda activate <env-name>
# pre-commit run --all-files
# python -m pip install .
# cd tests/scripts
# ./globus_auth.bash
local try_num=$1

PERLMUTTER_ENDPOINT=6bdc7956-fc0f-4ad2-989c-7aa5ee643a79

TRY_NUM=8
SRC_DIR=/lcrc/group/e3sm/ac.forsyth2/zstash_testing/test_globus_auth # Chrysalis
DST_DIR=globus://${PERLMUTTER_ENDPOINT}/global/homes/f/forsyth/zstash/tests/test_globus_auth_try${TRY_NUM}
DST_DIR=globus://${PERLMUTTER_ENDPOINT}/global/homes/f/forsyth/zstash/tests/test_globus_auth_try${try_num} # Perlmutter
# To start fresh with try_num=1, delete the above directory on Perlmutter before running. Example:
# rm -rf /global/homes/f/forsyth/zstash/tests/test_globus_auth_try1

GLOBUS_CFG=/home/ac.forsyth2/.globus-native-apps.cfg
INI_PATH=/home/ac.forsyth2/.zstash.ini
Expand Down Expand Up @@ -134,4 +118,4 @@ run_test_cases()
# Could also test -l and -v options, but the above code covers the important part.
}

run_test_cases
run_test_cases "$1"
75 changes: 75 additions & 0 deletions tests/integration/bash_tests/run_from_chrysalis/symlinks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Test symlinks
# Adjusted from https://github.com/E3SM-Project/zstash/issues/341

check_log_has()
{
local expected_grep="${1}"
local log_file="${2}"
grep -q "${expected_grep}" ${log_file}
if [ $? != 0 ]; then
echo "Expected grep '${expected_grep}' not found in ${log_file}. Test failed."
exit 2
fi
}

test_cases()
{
local follow_symlinks=$1
cd /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks
rm -rf workdir workdir2 workdir3
mkdir workdir workdir2 workdir3
cd workdir
mkdir -p src/d1 src/d2
touch src/d1/large_file.txt

# This creates a symlink in d2 that links to a file in d1
# Notice absolute path is used for source
ln -s /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir/src/d1/large_file.txt src/d2/large_file.txt

echo ""
echo "ls -l src/d2"
case_name="ls_1"
ls -l src/d2 2>&1 | tee ${case_name}.log
# symlink
check_log_has "large_file.txt -> /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir/src/d1/large_file.txt" ${case_name}.log

echo ""
case_name="create"
if [[ "${follow_symlinks,,}" == "true" ]]; then
echo "zstash create --hpss=none --follow-symlinks --cache /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir2 src/d2"
zstash create --hpss=none --follow-symlinks --cache /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir2 src/d2 2>&1 | tee ${case_name}.log
else
echo "zstash create --hpss=none --cache /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir2 src/d2"
zstash create --hpss=none --cache /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir2 src/d2 2>&1 | tee ${case_name}.log
fi
check_log_has "Adding 000000.tar" ${case_name}.log

echo ""
echo "ls -l src/d2"
case_name="ls_2"
ls -l src/d2 2>&1 | tee ${case_name}.log
# symlink (src is unaffected)
check_log_has "large_file.txt -> /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir/src/d1/large_file.txt" ${case_name}.log

cd ../workdir3
echo ""
echo "zstash extract --hpss=none --cache /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir2"
case_name="extract"
zstash extract --hpss=none --cache /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks/workdir2 2>&1 | tee ${case_name}.log
check_log_has "No failures detected when extracting the files" ${case_name}.log

cd ..
echo ""
echo "ls workdir3"
case_name="ls_3"
ls workdir3 2>&1 | tee ${case_name}.log
# large_file.txt
check_log_has "large_file.txt" ${case_name}.log

cd /home/ac.forsyth2/ez/zstash/tests/utils/test_symlinks
rm -rf workdir workdir2 workdir3 ls_3.log

}

test_cases true
test_cases false
Loading
Loading