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

Tests #39

Closed
wants to merge 8 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
26 changes: 25 additions & 1 deletion backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#: The REEV version from the file (``None`` if to load dynamically from git)
REEV_VERSION = None
# Try to obtain version from file, otherwise keep it at ``None``
if os.path.exists(VERSION_FILE):
if os.path.exists(VERSION_FILE): # pragma: no cover
with open(VERSION_FILE) as f:
REEV_VERSION = f.read().strip() or None

Expand Down Expand Up @@ -101,6 +101,30 @@ async def version():
return Response(content=version)


# Register app for returning proxy for variantvalidator.org.
@app.get("/variantvalidator/{path:path}")
async def variantvalidator(request: Request, path: str):
"""Implement reverse proxy for variantvalidator.org."""
url = request.url
# Change grch to GRCh and chr to nothing in path
path = path.replace("grch", "GRCh").replace("chr", "")
backend_url = "https://rest.variantvalidator.org/VariantValidator/variantvalidator/" + path

backend_url = backend_url + (f"?{url.query}" if url.query else "")
backend_req = client.build_request(
method=request.method,
url=backend_url,
content=await request.body(),
)
backend_resp = await client.send(backend_req, stream=True)
return StreamingResponse(
backend_resp.aiter_raw(),
status_code=backend_resp.status_code,
headers=backend_resp.headers,
background=BackgroundTask(backend_resp.aclose),
)


# Register route for favicon.
@app.get("/favicon.ico")
async def favicon():
Expand Down
43 changes: 43 additions & 0 deletions backend/tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import subprocess
import typing

import pytest
Expand Down Expand Up @@ -74,3 +75,45 @@ async def test_invalid_proxy_route(monkeypatch, httpx_mock):
response = client.get("/proxy/some-other-path")
assert response.status_code == 404
assert response.text == "Reverse proxy route not found"


@pytest.mark.asyncio
async def test_version(monkeypatch):
"""Test version endpoint."""
monkeypatch.setattr(main, "REEV_VERSION", "1.2.3")
response = client.get("/version")
assert response.status_code == 200
assert response.text == "1.2.3"


@pytest.mark.asyncio
async def test_version_no_version(monkeypatch):
"""Test version endpoint with no version."""
monkeypatch.setattr(main, "REEV_VERSION", None)
response = client.get("/version")
assert response.status_code == 200
expected = subprocess.check_output(["git", "describe", "--tags", "--dirty"]).strip().decode()
assert response.text == expected


@pytest.mark.asyncio
async def test_variantvalidator(monkeypatch, httpx_mock):
"""Test variant validator endpoint."""
variantvalidator_url = "https://rest.variantvalidator.org/VariantValidator/variantvalidator"
httpx_mock.add_response(
url=f"{variantvalidator_url}/{MOCKED_URL_TOKEN}",
method="GET",
text="Mocked response",
)

response = client.get(f"/variantvalidator/{MOCKED_URL_TOKEN}")
assert response.status_code == 200
assert response.text == "Mocked response"


@pytest.mark.asyncio
async def test_favicon():
"""Test favicon endpoint."""
response = client.get("/favicon.ico")
assert response.status_code == 200
assert response.headers["content-type"] == "image/vnd.microsoft.icon"
37 changes: 13 additions & 24 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"prettier": "^3.0.2",
"typescript": "~5.2.2",
"vite": "^4.3.9",
"vite-plugin-vuetify": "^1.0.2",
"vitest": "^0.32.4",
"vitest-fetch-mock": "^0.2.2",
"vue-cli-plugin-vuetify": "~2.5.8",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/api/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ describe('roundIt method', () => {

describe('search method', () => {
it('should return route location if match', () => {
const result = search('BRCA1', 'ghcr37')
const result = search('HGNC:1100', 'ghcr37')
expect(result).toEqual({
name: 'gene',
params: {
searchTerm: 'BRCA1',
searchTerm: 'HGNC:1100',
genomeRelease: 'ghcr37'
}
})
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/api/annonars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ export class AnnonarsClient {
})
return await response.json()
}

async fetchGenes(query: string): Promise<any> {
const response = await fetch(`${this.apiBaseUrl}genes/search?${query}`, {
method: 'GET'
})
return await response.json()
}
}
20 changes: 16 additions & 4 deletions frontend/src/api/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ export const isVariantMtHomopolymer = (smallVar: any): any => {
* the correct page.
*
* @param searchTerm The search term to use.
* @param genomeRelease The genome release to use.
*/
export const search = (searchTerm: string, genomeRelease: string) => {
interface RouteLocationFragment {
name: string
params?: any
query?: any
}

type RouteLoctionBuilder = () => RouteLocationFragment
Expand All @@ -96,24 +98,34 @@ export const search = (searchTerm: string, genomeRelease: string) => {
// first match.
const SEARCH_REGEXPS: [RegExp, RouteLoctionBuilder][] = [
[
/^chr\d+:\d+:[A-Z]:[A-Z]$/,
/^HGNC:\d+$/,
(): RouteLocationFragment => ({
name: 'variant',
name: 'gene',
params: {
searchTerm: searchTerm,
genomeRelease: genomeRelease
}
})
],
[
/^.*$/,
/^chr\d+:\d+:[A-Z]:[A-Z]$/,
(): RouteLocationFragment => ({
name: 'gene',
name: 'variant',
params: {
searchTerm: searchTerm,
genomeRelease: genomeRelease
}
})
],
[
/^.*$/,
(): RouteLocationFragment => ({
name: 'genes',
query: {
q: searchTerm,
fields: 'hgnc_id,ensembl_gene_id,ncbi_gene_id,symbol'
}
})
]
]

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/HeaderDefault.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ onMounted(() => {
alt="logo"
width="70"
/>
Explanation and Evaluation of Variants
REEV: Explanation and Evaluation of Variants
</router-link>
</v-toolbar-title>
<v-spacer></v-spacer>
Expand Down
20 changes: 19 additions & 1 deletion frontend/src/components/HeaderDetailPage.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
<script setup lang="ts">
import { ref } from 'vue'
import { watch, ref } from 'vue'
import { useRouter } from 'vue-router'

import SearchBar from '@/components/SearchBar.vue'
import { search } from '@/api/utils'

export interface Props {
searchTerm?: string
genomeRelease?: string
}

const props = withDefaults(defineProps<Props>(), {
searchTerm: '',
genomeRelease: 'grch37'
})

const router = useRouter()

const searchTermRef = ref(props.searchTerm)
const genomeReleaseRef = ref(props.genomeRelease)

/**
* Perform a search based on the current search term and genome release.
*
* If a route is found for the search term then redirect to that route.
* Otherwise log an error.
*/
const performSearch = async () => {
const routeLocation: any = search(searchTermRef.value, genomeReleaseRef.value)
if (routeLocation) {
Expand All @@ -22,6 +34,12 @@ const performSearch = async () => {
console.error(`no route found for ${searchTermRef.value}`)
}
}

const updateTerms = async () => {
searchTermRef.value = props.searchTerm
}

watch(() => props.searchTerm, updateTerms)
</script>

<template>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/VariantDetails/BeaconNetwork.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const loadBeacon = () => {
Query Beacon -----|>
<v-btn prepend-icon="mdi-refresh" style="float: right" @click="loadBeacon()"> Load </v-btn>
</h3>
<div class="card-body">
<div>
<iframe
v-if="beaconAddress"
ref="beaconFrame"
Expand Down
Loading