Skip to content

Commit

Permalink
Merge pull request #27 from AgPipeline/develop
Browse files Browse the repository at this point in the history
Merge develop into master
  • Loading branch information
Chris-Schnaufer authored Sep 11, 2020
2 parents 4e4625c + 7865817 commit a3c1868
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 29 deletions.
67 changes: 67 additions & 0 deletions .github/workflows/docker_test_check_rgb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash

# Checking the results of running the docker commands

# Define expected results
EXPECTED_FILES=("result.json")
EXPECTED_CANOPYCOVER_VALUES=(99.75714285714285 20.91874906479126)

# What folder are we looking in for outputs
if [[ ! "${1}" == "" ]]; then
TARGET_FOLDER="${1}"
else
TARGET_FOLDER="./outputs"
fi

# What our target file to read is
if [[ ! "${2}" == "" ]]; then
CHECK_FILE="${2}"
else
CHECK_FILE="canopycover.csv"
fi
EXPECTED_FILES+=("${CHECK_FILE}")

# Check if expected files are found
for i in $(seq 0 $(( ${#EXPECTED_FILES[@]} - 1 )))
do
if [[ ! -f "${TARGET_FOLDER}/${EXPECTED_FILES[$i]}" ]]; then
echo "Expected file ${EXPECTED_FILES[$i]} is missing"
exit 10
fi
done

# Check the results of the canopy cover calculation
RESULT_VALUES=(`gawk '
BEGIN {
FPAT = "([^,]+)|(\"[^\"]+\")"
}
{
if ($1 != "local_datetime") { # Skipping the header line
printf("%s\n", $2)
}
}
END {
}
' "${TARGET_FOLDER}/${CHECK_FILE}"`)

echo "Result counts: ${#EXPECTED_CANOPYCOVER_VALUES[@]} vs ${#RESULT_VALUES[@]}"
if [[ ${#EXPECTED_CANOPYCOVER_VALUES[@]} != ${#RESULT_VALUES[@]} ]]; then
echo "Number of results found in file (${#RESULT_VALUES[@]}) don't match expected count (${#EXPECTED_CANOPYCOVER_VALUES[@]})"
if [[ ${#RESULT_VALUES[@]} > 0 ]]; then
for i in $(seq 0 $(( ${#RESULT_VALUES[@]} - 1 )))
do
echo "${i}: ${RESULT_VALUES[$i]}"
done
fi
exit 20
fi

for i in $(seq 0 $(( ${#EXPECTED_CANOPYCOVER_VALUES[@]} - 1 )))
do
if [[ "${EXPECTED_CANOPYCOVER_VALUES[$i]}" == "${RESULT_VALUES[$i]}" ]]; then
echo "Values for index ${i} match: '${RESULT_VALUES[$i]}' '${EXPECTED_CANOPYCOVER_VALUES[$i]}'"
else
echo "Result value for index ${i}: '${RESULT_VALUES[$i]}' doesn't match expected: '${EXPECTED_CANOPYCOVER_VALUES[$i]}'"
exit 30
fi
done
8 changes: 3 additions & 5 deletions .github/workflows/testing_checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
branches:
- master
- develop
- adding_testing
pull_request:
branches:
- master
Expand All @@ -22,7 +21,7 @@ jobs:
include:
- app: pylint
pip_installs: pylint
test_command: cat action_test_files.txt | xargs python3 -m pylint --rcfile ./pylint.rc
test_command: (cat action_test_files.txt | xargs python3 -m pylint --rcfile ./pylint.rc) && (find ./tests | grep '\.py' | xargs python3 -m pylint -d duplicate-code --rcfile ./pylint.rc)
- app: pytest
pip_installs: pytest pytest-cov
test_command: python3 -m pytest --cov=. -rpP --cov-report=xml > coverage.txt
Expand All @@ -34,7 +33,6 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: '3.7'
id: install_python_3_7
- name: Updated python version
run: python3 --version
- name: PYTHONPATH environment variable
Expand All @@ -54,7 +52,7 @@ jobs:
- name: Fetch source code
uses: actions/checkout@v2
- name: Finding files to process
run: find . -type f -name "*.py" > action_test_files.txt
run: find . -type f -name "*.py" | grep -v '/tests/' > action_test_files.txt
- name: Install system requirements
shell: bash
run: 'sudo apt-get install -y python3-gdal gdal-bin libgdal-dev gcc g++ python3.7-dev'
Expand Down Expand Up @@ -87,7 +85,7 @@ jobs:
- name: Upload testing artifact
uses: actions/upload-artifact@v2
with:
name: testing_artifacts
name: Testing artifacts ${{ matrix.app }}
path: ${{ matrix.artifacts }}
if: ${{ matrix.artifacts }}
- name: Upload coverage to Codecov
Expand Down
65 changes: 65 additions & 0 deletions .github/workflows/testing_docker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Testing Docker image
on:
push:
branches:
- master
- develop
pull_request:
branches:
- master
- develop
tags:
- v*

jobs:
docker_testing:
runs-on: ubuntu-latest
name: Running Docker testing
steps:
- name: Fetch source code
uses: actions/checkout@v2
- name: Create folders
run: |
mkdir ./inputs && chmod 777 ./inputs
mkdir ./outputs && chmod 777 ./outputs
- name: List folder contents
run: |
echo "Current folder" && ls -la
echo "test_data" && ls -l ./test_data
- name: Copy testing data files
run: |
cp "${PWD}/test_data"/* "${PWD}/inputs/"
echo "inputs" && ls -l ./inputs
- name: Folder contents
run: |
echo "Current folder" && ls -l
echo "Inputs folder" && ls -l ./inputs
echo "Outputs folder" && ls -l ./outputs
- name: Build docker image
run: docker build -t canopycover_test:latest ./
- name: Compress docker image
run: docker save canopycover_test:latest | gzip -7 -c - > canopycover_test_image.tar.gz
- name: Upload docker image
uses: actions/upload-artifact@v2
with:
name: canopycover_test_image
path: canopycover_test_image.tar.gz
- name: Run docker test
run: docker run --rm -v "${PWD}/inputs:/inputs" -v "${PWD}/outputs:/outputs" canopycover_test:latest --working_space /outputs --metadata /inputs/meta.yaml /inputs/rgb_17_7_W.tif /inputs/mask_1.tif
- name: Output folder contents
run: echo "Outputs folder" && ls -l ./outputs
- name: Check outputs
run: |
cat outputs/canopycover.csv
chmod +x "./.github/workflows/docker_test_check_rgb.sh"
"./.github/workflows/docker_test_check_rgb.sh"
artifact_cleanup:
runs-on: ubuntu-latest
needs: [docker_testing]
name: Cleanup artifacts upon success
steps:
- name: Remove docker artifact
uses: geekyeggo/delete-artifact@v1
with:
name: canopycover_test_image
49 changes: 48 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,53 @@
FROM agdrone/agpypeline:1.0
FROM ubuntu:18.04
LABEL maintainer="Chris Schnaufer <[email protected]>"

# Add user
RUN useradd -u 49044 extractor \
&& mkdir /home/extractor
RUN chown -R extractor /home/extractor \
&& chgrp -R extractor /home/extractor

# Install the Python version we want
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
python3.7 \
python3-pip && \
ln -sfn /usr/bin/python3.7 /usr/bin/python && \
ln -sfn /usr/bin/python3.7 /usr/bin/python3 && \
ln -sfn /usr/bin/python3.7m /usr/bin/python3m && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Perform some upgrades
RUN python3 -m pip install --upgrade --no-cache-dir pip
RUN python3 -m pip install --upgrade --no-cache-dir setuptools

# Install applications we need
RUN apt-get update && \
apt-get install -y --no-install-recommends \
python3-gdal \
gdal-bin \
libgdal-dev \
gcc \
g++ \
python3.7-dev && \
python3 -m pip install --upgrade --no-cache-dir \
wheel && \
python3 -m pip install --upgrade --no-cache-dir \
numpy && \
python3 -m pip install --upgrade --no-cache-dir \
pygdal==2.2.3.* && \
apt-get remove -y \
libgdal-dev \
gcc \
g++ \
python3-dev && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

COPY requirements.txt packages.txt /home/extractor/

USER root
Expand Down
66 changes: 46 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,24 @@ This algorithm expects a one-layer geotiff file with the extention .tif or .tiff
## Use

### Sample Docker Command line
First build the Docker image using the Dockerfile, which in this case will be named agpipeline/canopycover:3.0
Read up on [docker build](https://docs.docker.com/engine/reference/commandline/build/) if needed.

```docker build -t agpipeline/canopycover:3.0 ./```
First build the Docker image, using the Dockerfile, and tag it agdrone/transformer-canopycover:1.1.
Read about the [docker build](https://docs.docker.com/engine/reference/commandline/build/) command if needed.

```bash
docker build -t agdrone/transformer-canopycover:1.1 ./
```

Below is a sample command line that shows how the canopy cover Docker image could be run.
An explanation of the command line options used follows.
Be sure to read up on the [docker run](https://docs.docker.com/engine/reference/run/) command line for more information.

```docker run --rm --mount "src=/home/test,target=/mnt,type=bind" -e "BETYDB_URL=https://terraref.ncsa.illinois.edu/bety/" -e "BETYDB_KEY=<key value>" agpipeline/canopycover:3.0 --working_space "/mnt" --metadata "/mnt/08f445ef-b8f9-421a-acf1-8b8c206c1bb8_metadata.json" --citation_author "Me Myself" --citation_title "Something in the green" --citation_year "2019" --germplasm_name "Big Plant" "/mnt/rgb_mask_L2_my-site_2018-10-01__14-20-40_mask.tif"```
```bash
docker run --rm --mount "src=${PWD}/test_data,target=/mnt,type=bind" agdrone/transformer-canopycover:1.1 --working_space "/mnt" --metadata "/mnt/experiment.yaml" --citation_author "Me Myself" --citation_title "Something in the green" --citation_year "2019" --germplasm_name "Big Plant" "/mnt/rgb_1_2_E.tif"
```

This example command line assumes the source files are located in the `/home/test` folder of the local machine.
The name of the image to run is `agpipeline/canopycover:3.0`.
This example command line assumes the source files are located in the `test_data` folder off the current folder.
The name of the image to run is `agdrone/transformer-canopycover:1.1`.

We are using the same folder for the source metadata and the cleaned metadata.
By using multiple `--mount` options, the source and output files can be separated.
Expand All @@ -47,22 +52,20 @@ Everything between 'docker' and the name of the image are docker commands.

- `run` indicates we want to run an image
- `--rm` automatically delete the image instance after it's run
- `--mount "src=/home/test,target=/mnt,type=bind"` mounts the `/home/test` folder to the `/mnt` folder of the running image
- `-e "BETYDB_URL=https://terraref.ncsa.illinois.edu/bety/"` the URL to the BETYdb instance to fetch plot boundaries, and other data, from
- `-e "BETYDB_KEY=<key value>"` the key associated with the BETYdb URL (replace `<key value>` with value of your key)
- `--mount "src=${PWD}/test_data,target=/mnt,type=bind"` mounts the `${PWD}/test` folder to the `/mnt` folder of the running image

We mount the `/home/test` folder to the running image to make available the file to the software in the image.
We mount the `${PWD}/test` folder to the running image to make available the file to the software in the image.

**Image's commands** \
The command line parameters after the image name are passed to the software inside the image.
Note that the paths provided are relative to the running image (see the --mount option specified above).

- `--working_space "/mnt"` specifies the folder to use as a workspace
- `--metadata "/mnt/08f445ef-b8f9-421a-acf1-8b8c206c1bb8_metadata.json"` is the name of the source metadata to be cleaned
- `--citation_author "<author name>"` the name of the author to cite in the resulting CSV file(s)
- `--citation_title "<title>"` the title of the citation to store in the resulting CSV file(s)
- `--citation_year "<year>"` the year of the citation to store in the resulting CSV file(s)
- `"/mnt/rgb_mask_L2_my-site_2018-10-01__14-20-40_mask.tif"` the names of one or more image files to use when calculating plot-level canopy cover
- `--metadata "/mnt/experiment.yaml"` is the name of the source metadata to be cleaned
- `--citation_author "Me Myself"` the name of the author to cite in the resulting CSV file(s)
- `--citation_title "Something in the green"` the title of the citation to store in the resulting CSV file(s)
- `--citation_year "2019"` the year of the citation to store in the resulting CSV file(s)
- `"mnt/rgb_1_2_E.tif"` the names of one or more image files to use when calculating plot-level canopy cover

**Testing the Docker Transformer** \
In order to make sure that the canopy cover transformer is functioning correctly, create an image that is all black
Expand All @@ -80,13 +83,31 @@ Once you have used the transformer on your image data, you can upload your docke
so that it can be accessed remotely. Use a tutorial such as [this one](https://ropenscilabs.github.io/r-docker-tutorial/04-Dockerhub.html)
in order to upload your image to Docker Hub

## Testing Source Code
## Acceptance Testing

There are automated test suites that are run via [GitHub Actions](https://docs.github.com/en/actions).
In this section we provide details on these tests so that they can be run locally as well.

These tests are run when a [Pull Request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) or [push](https://docs.github.com/en/github/using-git/pushing-commits-to-a-remote-repository) occurs on the `develop` or `master` branches.
There may be other instances when these tests are automatically run, but these are considered the mandatory events and branches.

### PyLint and PyTest

These tests are run against any Python scripts that are in the repository.

[PyLint](https://www.pylint.org/) is used to both check that Python code conforms to the recommended coding style, and checks for syntax errors.
The default behavior of PyLint is modified by the `pylint.rc` file in the [Organization-info](https://github.com/AgPipeline/Organization-info) repository.
Please also refer to our [Coding Standards](https://github.com/AgPipeline/Organization-info#python) for information on how we use [pylint](https://www.pylint.org/).
A pylint command line is:

The following command can be used to fetch the `pylint.rc` file:
```bash
wget https://raw.githubusercontent.com/AgPipeline/Organization-info/master/pylint.rc
```

Assuming the `pylint.rc` file is in the current folder, the following command can be used against the `canopycover.py` file:
```bash
# Assumes Python3.7+ is default Python version
python -m pylint --rcfile ~/agpipeline/Organization-info/pylint.rc canopycover.py
python -m pylint --rcfile ./pylint.rc canopycover.py
```

In the `tests` folder there are testing scripts and their supporting files.
Expand All @@ -99,9 +120,14 @@ The command line for running the tests is as follows:
python -m pytest -rpP
```

If test coverage reporting is desired, we suggest using [pytest-cov](https://pytest-cov.readthedocs.io/en/latest/).
After installing this tool, the following command line will include a coverage report in the output:
If [pytest-cov](https://pytest-cov.readthedocs.io/en/latest/) is installed, it can be used to generate a code coverage report as part of running PyTest.
The code coverage report shows how much of the code has been tested; it doesn't indicate **how well** that code has been tested.
The modified PyTest command line including coverage is:
```bash
# Assumes Python3.7+ is default Python version
python -m pytest --cov=. -rpP
```

### Docker Testing

The Docker testing Workflow replicate the examples in this document to ensure they continue to work.
Loading

0 comments on commit a3c1868

Please sign in to comment.