Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI] Add CI Testing Support #10

Closed
wants to merge 6 commits into from
Closed
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
21 changes: 21 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ jobs:
- checks
- conda-python-build
- wheel-build-nx-cugraph
- conda-notebook-tests
- conda-python-tests
- docs-build
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
if: always()
Expand All @@ -38,6 +41,24 @@ jobs:
checks:
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
conda-python-build:
needs: checks
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
with:
build_type: pull-request
conda-python-tests:
needs: [conda-python-build, changed-files]
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python
with:
build_type: pull-request
conda-notebook-tests:
needs: [conda-python-build, changed-files]
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_notebooks
with:
enable_check_generated_files: false
conda-python-build:
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ __pycache__
.coverage
.vscode
.lock
*.swp
*.sw?
*.pytest_cache
*~
DartConfiguration.tcl
Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ repos:
- id: nx-cugraph-meta-data-update
name: nx-cugraph meta-data updater
entry: bash -c "PYTHONPATH=. python _nx_cugraph/__init__.py"
files: ^nx_cugraph
files: ^(nx_cugraph|_nx_cugraph)/
types: [python]
language: python
pass_filenames: false
Expand All @@ -104,9 +104,9 @@ repos:
hooks:
- id: nx-cugraph-readme-update
name: nx-cugraph README updater
entry: bash -c "PYTHONPATH=. python ./scripts/update_readme.py ./README.md"
files: ^nx_cugraph/
entry: bash -c "PYTHONPATH=. python scripts/update_readme.py README.md"
files: ^(nx_cugraph|_nx_cugraph)/
types_or: [python, markdown]
language: python
pass_filenames: false
additional_dependencies: ["networkx>=3.3"]
additional_dependencies: ["networkx>=3.4"]
105 changes: 105 additions & 0 deletions ci/notebook_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Copyright (c) 2021-2024, NVIDIA CORPORATION.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import re
import argparse
import sys
import glob
from pathlib import Path

from numba import cuda

# for adding another run type and skip file name add to this dictionary
runtype_dict = {
"all": "",
"ci": "SKIP_CI_TESTING",
"nightly": "SKIP_NIGHTLY",
"weekly": "SKIP_WEEKLY",
}


def skip_book_dir(runtype):
# Add all run types here, currently only CI supported

if runtype in runtype_dict.keys():
if Path(runtype_dict.get(runtype)).is_file():
return True
return False


cuda_version_string = ".".join([str(n) for n in cuda.runtime.get_version()])
#
# Not strictly true... however what we mean is
# Pascal or earlier
#
ampere = False
device = cuda.get_current_device()

parser = argparse.ArgumentParser(description="Condition for running the notebook tests")
parser.add_argument("runtype", type=str)

args = parser.parse_args()

runtype = args.runtype

if runtype not in runtype_dict.keys():
print(f"Unknown Run Type = {runtype}", file=sys.stderr)
exit()


# check for the attribute using both pre and post numba 0.53 names
cc = getattr(device, "COMPUTE_CAPABILITY", None) or getattr(
device, "compute_capability"
)
if cc[0] >= 8:
ampere = True

skip = False
for filename in glob.iglob("**/*.ipynb", recursive=True):
skip = False
if skip_book_dir(runtype):
print(
f"SKIPPING {filename} (Notebook skipped for run type {runtype}) "
"due to skip file in folder.",
file=sys.stderr,
)
skip = True
else:
for line in open(filename, "r"):
if re.search("# Skip notebook test", line):
skip = True
print(f"SKIPPING {filename} (marked as skip)", file=sys.stderr)
break
elif re.search("dask", line):
print(
f"SKIPPING {filename} (suspected Dask usage, not "
"currently automatable)",
file=sys.stderr,
)
skip = True
break
elif ampere and re.search("# Does not run on Ampere", line):
print(f"SKIPPING {filename} (does not run on Ampere)", file=sys.stderr)
skip = True
break
elif re.search("# Does not run on CUDA ", line) and (
cuda_version_string in line
):
print(
f"SKIPPING {filename} (does not run on CUDA {cuda_version_string})",
file=sys.stderr,
)
skip = True
break
if not skip:
print(filename)
10 changes: 10 additions & 0 deletions ci/run_nx_cugraph_pytests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
# Copyright (c) 2024, NVIDIA CORPORATION.

set -euo pipefail

# Support invoking run_nx_cugraph_pytests.sh outside the script directory
cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")"/../nx_cugraph

NX_CUGRAPH_USE_COMPAT_GRAPHS=False pytest --capture=no --cache-clear --benchmark-disable "$@" tests
NX_CUGRAPH_USE_COMPAT_GRAPHS=True pytest --capture=no --cache-clear --benchmark-disable "$@" tests
66 changes: 66 additions & 0 deletions ci/test_notebooks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash
# Copyright (c) 2020-2024, NVIDIA CORPORATION.

set -Eeuo pipefail

. /opt/conda/etc/profile.d/conda.sh

RAPIDS_VERSION_MAJOR_MINOR="$(rapids-version-major-minor)"

rapids-logger "Generate notebook testing dependencies"
rapids-dependency-file-generator \
--output conda \
--file-key test_notebooks \
--matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml

rapids-mamba-retry env create --yes -f env.yaml -n test

# Temporarily allow unbound variables for conda activation.
set +u
conda activate test
set -u

rapids-print-env

rapids-logger "Downloading artifacts from previous jobs"
CPP_CHANNEL=$(rapids-download-conda-from-s3 cpp)
PYTHON_CHANNEL=$(rapids-download-conda-from-s3 python)

rapids-mamba-retry install \
--channel "${CPP_CHANNEL}" \
--channel "${PYTHON_CHANNEL}" \
"libcugraph=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
"pylibcugraph=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
"nx-cugraph=${RAPIDS_VERSION_MAJOR_MINOR}.*"

NBTEST="$(realpath "$(dirname "$0")/utils/nbtest.sh")"
NOTEBOOK_LIST="$(realpath "$(dirname "$0")/notebook_list.py")"
EXITCODE=0
trap "EXITCODE=1" ERR


pushd notebooks
TOPLEVEL_NB_FOLDERS="$(find . -name "*.ipynb" | cut -d'/' -f2 | sort -u)"
set +e
# Always run nbtest in all TOPLEVEL_NB_FOLDERS, set EXITCODE to failure
# if any run fails
for folder in ${TOPLEVEL_NB_FOLDERS}; do
rapids-logger "Folder: ${folder}"
pushd "${folder}"
NBLIST=$(python "${NOTEBOOK_LIST}" ci)
for nb in ${NBLIST}; do
nbBasename=$(basename "${nb}")
pushd "$(dirname "${nb}")"
nvidia-smi
${NBTEST} "${nbBasename}"
echo "Ran nbtest for $nb : return code was: $?, test script exit code is now: $EXITCODE"
echo
popd
done
popd
done

nvidia-smi

echo "Notebook test script exiting with value: ${EXITCODE}"
exit ${EXITCODE}
99 changes: 99 additions & 0 deletions ci/test_python.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/bash
# Copyright (c) 2022-2024, NVIDIA CORPORATION.

set -euo pipefail

# Support invoking test_python.sh outside the script directory
cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")"/../

. /opt/conda/etc/profile.d/conda.sh

RAPIDS_VERSION_MAJOR_MINOR="$(rapids-version-major-minor)"

rapids-logger "Generate Python testing dependencies"
rapids-dependency-file-generator \
--output conda \
--file-key test_python \
--matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml

rapids-mamba-retry env create --yes -f env.yaml -n test

# Temporarily allow unbound variables for conda activation.
set +u
conda activate test
set -u

rapids-logger "Downloading artifacts from previous jobs"
CPP_CHANNEL=$(rapids-download-conda-from-s3 cpp)
PYTHON_CHANNEL=$(rapids-download-conda-from-s3 python)

RAPIDS_TESTS_DIR=${RAPIDS_TESTS_DIR:-"${PWD}/test-results"}
RAPIDS_COVERAGE_DIR=${RAPIDS_COVERAGE_DIR:-"${PWD}/coverage-results"}
mkdir -p "${RAPIDS_TESTS_DIR}" "${RAPIDS_COVERAGE_DIR}"

rapids-print-env

rapids-mamba-retry install \
--channel "${CPP_CHANNEL}" \
--channel "${PYTHON_CHANNEL}" \
"libcugraph=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
"pylibcugraph=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
"nx-cugraph=${RAPIDS_VERSION_MAJOR_MINOR}.*" \

rapids-logger "Check GPU usage"
nvidia-smi

export LD_PRELOAD="${CONDA_PREFIX}/lib/libgomp.so.1"

EXITCODE=0
trap "EXITCODE=1" ERR
set +e

# Test runs that include tests that use dask require
# --import-mode=append. Those tests start a LocalCUDACluster that inherits
# changes from pytest's modifications to PYTHONPATH (which defaults to
# prepending source tree paths to PYTHONPATH). This causes the
# LocalCUDACluster subprocess to import cugraph from the source tree instead of
# the install location, and in most cases, the source tree does not have
# extensions built in-place and will result in ImportErrors.
#
rapids-logger "pytest nx-cugraph"
./ci/run_nx_cugraph_pytests.sh \
--verbose \
--junitxml="${RAPIDS_TESTS_DIR}/junit-nx-cugraph.xml" \
--cov-config=../../.coveragerc \
--cov=nx_cugraph \
--cov-report=xml:"${RAPIDS_COVERAGE_DIR}/nx-cugraph-coverage.xml" \
--cov-report=term

rapids-logger "pytest networkx using nx-cugraph backend"
pushd nx_cugraph
../run_nx_tests.sh
# run_nx_tests.sh outputs coverage data, so check that total coverage is >0.0%
# in case nx-cugraph failed to load but fallback mode allowed the run to pass.
_coverage=$(coverage report|grep "^TOTAL")
echo "nx-cugraph coverage from networkx tests: $_coverage"
echo $_coverage | awk '{ if ($NF == "0.0%") exit 1 }'
# Ensure all algorithms were called by comparing covered lines to function lines.
# Run our tests again (they're fast enough) to add their coverage, then create coverage.json
NX_CUGRAPH_USE_COMPAT_GRAPHS=False pytest \
--pyargs nx_cugraph \
--config-file=../pyproject.toml \
--cov-config=../pyproject.toml \
--cov=nx_cugraph \
--cov-append \
--cov-report=
coverage report \
--include="*/nx_cugraph/algorithms/*" \
--omit=__init__.py \
--show-missing \
--rcfile=../pyproject.toml
coverage json --rcfile=../pyproject.toml
python -m nx_cugraph.tests.ensure_algos_covered
# Exercise (and show results of) scripts that show implemented networkx algorithms
python -m nx_cugraph.scripts.print_tree --dispatch-name --plc --incomplete --different
python -m nx_cugraph.scripts.print_table
popd

rapids-logger "Test script exiting with value: $EXITCODE"
exit ${EXITCODE}
Loading
Loading