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

some new tests, and reconfiguring #51

Merged
merged 16 commits into from
Jan 15, 2025
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
2 changes: 1 addition & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ New unit test suggestions are tracked as GitHub issues. When creating a unit tes
4. Ensure your proposed WDL runs locally via `miniwdl run` or `java -jar cromwell-86.jar run`
5. If you are user of PROOF, please also make sure to test that the WDL unit test runs via PROOF.
- If your WDL succeeds locally but fails in PROOF, please report the issue in the [proof-api repo](https://github.com/FredHutch/proof-api/issues).
6. Add the WDL to a subdirectory by the same name, i.e. `coolUnitTest/coolUnitTest.wdl`
6. Add the WDL to a subdirectory by the same name, i.e. `coolUnitTest/coolUnitTest.wdl`. If the WDL is expected to fail WOMtool the subdirectory AND the WDL file name must start with `badVal`. If the WDL is expected to fail both WOMtool and a Cromwell run, then the subdirectory AND the WDL file name must start with `badRun`.
7. Make sure to include an `inputs.json` and `options.json` if required and make sure that any other. input files referenced in `inputs.json` are provided in the same directory.
8. Add a README to the WDL's subdirectory describing the unit test's functionality and purpose.
9. Commit and push your proposed changes to GitHub.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/api-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ jobs:
- name: Run tests
env:
PROOF_API_TOKEN_DEV: ${{ secrets.PROOF_API_TOKEN_DEV }}
run: uv run pytest tests/cromwell-api/ --verbose
run: uv run pytest tests/cromwellapi/ --verbose
15 changes: 15 additions & 0 deletions badRunParseBatchFile/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# parseBatchFile WDL Workflow

## Overview
xxx

## Workflow Components

### Workflow: `parseBatchFile`
xxx

## Purpose
To check Cromwell failures behavior

## Version
WDL 1.0
46 changes: 46 additions & 0 deletions badRunParseBatchFile/badRunParseBatchFile.wdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
version 1.0
# This workflow takes a tab separated file where each row is a set of data to be used in each
# of the independent scattered task series that you have as your workflow process. This file
# will, for example, have column names `sampleName`, `bamLocation`, and `bedlocation`. This
# allows you to know that regardless of the order of the columns in your batch file, the correct
# inputs will be used for the tasks you define.
workflow parseBatchFile {
input {
File batchFile
}
Array[Object] batchInfo = read_objects(batchFile)
scatter (job in batchInfo){
String sampleName = job.sampleName
File bamFile = job.bamLocation
File bedFile = job.bedLocation

## INSERT YOUR WORKFLOW TO RUN PER LINE IN YOUR BATCH FILE HERE!!!!
call test {
input: in1=sampleName, in2=bamFile, in3=bedFile
}

} # End Scatter over the batch file
# Outputs that will be retained when execution is complete
output {
Array[File] outputArray = test.item_out
}
# End workflow
}

#### TASK DEFINITIONS
# echo some text to stdout, treats files as strings just to echo them as a dummy example
task test {
input {
String in1
String in2
String in3
}
command {
echo ~{in1}
echo ~{in2}
echo ~{in3}
}
output {
File item_out = stdout()
}
}
10 changes: 10 additions & 0 deletions badValMissingValue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# badValMissingValue WDL Workflow

## Overview
A test workflow that demonstrates an invalid WDL.

### Expected error

```
Cannot lookup value 'docker_image', it is never declared. Available values are: ['str']
```
File renamed without changes.
71 changes: 0 additions & 71 deletions tests/cromwell-api/cromwell.py

This file was deleted.

19 changes: 0 additions & 19 deletions tests/cromwell-api/test-metadata.py

This file was deleted.

8 changes: 0 additions & 8 deletions tests/cromwell-api/test-submit.py

This file was deleted.

10 changes: 0 additions & 10 deletions tests/cromwell-api/utils.py

This file was deleted.

10 changes: 8 additions & 2 deletions tests/cromwell-api/conftest.py → tests/cromwellapi/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pathlib import Path

import pytest

from cromwell import CromwellApi
from proof import ProofApi

Expand All @@ -13,7 +14,7 @@ def cromwell_api():
return CromwellApi(url=cromwell_url)


@pytest.fixture(scope="session", autouse=True)
@pytest.fixture(scope="session")
def submit_wdls(cromwell_api):
"""
This fixture runs automatically before any tests.
Expand All @@ -25,7 +26,12 @@ def submit_wdls(cromwell_api):

print(f"Submitting {len(wdl_paths)} wdls ...")

out = [cromwell_api.submit_workflow(wdl_path=path) for path in wdl_paths]
out = []
for path in wdl_paths:
opts_path = path.parent / "options.json"
opts_path = opts_path if opts_path.exists() else None
res = cromwell_api.submit_workflow(wdl_path=path, options=opts_path)
out.append(res)

# Yield to let tests run
yield out
Expand Down
144 changes: 144 additions & 0 deletions tests/cromwellapi/cromwell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import httpx
from tenacity import (
retry,
retry_if_exception_type,
stop_after_attempt,
wait_exponential,
)

from utils import TOKEN, past_date


def as_file_object(path=None):
if not path:
return None
return open(path, mode="rb")


def my_before_sleep(state):
print(
f"Retrying in {state.next_action.sleep} seconds, attempt {state.attempt_number}"
)


def path_as_string(x):
if not x:
return None
return str(x.absolute())


class CromwellApi(object):
"""CromwellApi class"""

def __init__(self, url):
self.base_url = url.rstrip("/")
self.token = TOKEN
self.headers = {"Authorization": f"Bearer {TOKEN}"}

def submit_workflow(
self,
wdl_path,
inputs=None,
labels=None,
options=None,
):
files = {
"workflowSource": as_file_object(path_as_string(wdl_path)),
"workflowInputs": as_file_object(path_as_string(inputs)),
"labels": as_file_object(path_as_string(labels)),
"workflowOptions": as_file_object(path_as_string(options)),
}
files = {k: v for k, v in files.items() if v}
res = httpx.post(
f"{self.base_url}/api/workflows/v1", headers=self.headers, files=files
)
res.raise_for_status()
data = res.json()
data["path"] = str(wdl_path)
return data

@retry(
retry=retry_if_exception_type(httpx.HTTPStatusError),
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10),
before_sleep=my_before_sleep,
)
def metadata(self, workflow_id, params={}):
res = httpx.get(
f"{self.base_url}/api/workflows/v1/{workflow_id}/metadata",
headers=self.headers,
params=params,
)
res.raise_for_status()
return res.json()

def version(self):
res = httpx.get(
f"{self.base_url}/engine/v1/version",
headers=self.headers,
)
res.raise_for_status()
return res.json()

def validate(self, wdl_path, inputs=None, options=None):
files = {
"workflowSource": as_file_object(path_as_string(wdl_path)),
"workflowInputs": as_file_object(path_as_string(inputs)),
"workflowOptions": as_file_object(path_as_string(options)),
}
files = {k: v for k, v in files.items() if v}
res = httpx.post(
f"{self.base_url}/api/womtool/v1/describe",
headers=self.headers,
files=files,
)
res.raise_for_status()
return res.json()

def abort(self, workflow_id):
res = httpx.post(
f"{self.base_url}/api/workflows/v1/{workflow_id}/abort",
headers=self.headers,
)
res.raise_for_status()
return res.json()

def search(self, days=1, name=None, status=None):
submission = f"{past_date(days)}T00:00Z"
params = {"submission": submission, "name": name, "status": status}
params = {k: v for k, v in params.items() if v}
res = httpx.get(
f"{self.base_url}/api/workflows/v1/query",
headers=self.headers,
params=params,
)
res.raise_for_status()
return res.json()

@retry(
retry=retry_if_exception_type(httpx.HTTPStatusError),
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10),
before_sleep=my_before_sleep,
)
def outputs(self, workflow_id):
res = httpx.get(
f"{self.base_url}/api/workflows/v1/{workflow_id}/outputs",
headers=self.headers,
)
res.raise_for_status()
return res.json()

@retry(
retry=retry_if_exception_type(httpx.HTTPStatusError),
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10),
before_sleep=my_before_sleep,
)
def labels(self, workflow_id):
res = httpx.get(
f"{self.base_url}/api/workflows/v1/{workflow_id}/labels",
headers=self.headers,
)
res.raise_for_status()
return res.json()
1 change: 1 addition & 0 deletions tests/cromwellapi/labels1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"workflowType": "AppSubmission", "Label": "one", "secondaryLabel": "two"}
1 change: 1 addition & 0 deletions tests/cromwell-api/proof.py → tests/cromwellapi/proof.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import httpx

from utils import PROOF_BASE_URL, TOKEN


Expand Down
Loading
Loading