Skip to content

Commit

Permalink
feat: add /sample to query paths #501
Browse files Browse the repository at this point in the history
  • Loading branch information
fengelniederhammer committed Dec 14, 2023
1 parent 556552f commit 60ad1a6
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private class ProtectedDataAuthorizationFilter(
AMINO_ACID_MUTATIONS_ROUTE,
NUCLEOTIDE_INSERTIONS_ROUTE,
AMINO_ACID_INSERTIONS_ROUTE,
)
).map { "/sample$it" }
}

override fun isAuthorizedForEndpoint(request: CachedBodyHttpServletRequest): AuthorizationResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

Expand All @@ -70,6 +71,7 @@ const val ALIGNED_NUCLEOTIDE_SEQUENCES_ROUTE = "/alignedNucleotideSequences"
const val ALIGNED_AMINO_ACID_SEQUENCES_ROUTE = "/alignedAminoAcidSequences"

@RestController
@RequestMapping("/sample")
class LapisController(
private val siloQueryModel: SiloQueryModel,
private val requestContext: RequestContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

Expand All @@ -35,6 +36,7 @@ const val IS_MULTI_SEGMENT_SEQUENCE_EXPRESSION =

@RestController
@ConditionalOnExpression(IS_MULTI_SEGMENT_SEQUENCE_EXPRESSION)
@RequestMapping("/sample")
class MultiSegmentedSequenceController(
private val siloQueryModel: SiloQueryModel,
private val requestContext: RequestContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

Expand All @@ -35,6 +36,7 @@ const val IS_SINGLE_SEGMENT_SEQUENCE_EXPRESSION =

@RestController
@ConditionalOnExpression(IS_SINGLE_SEGMENT_SEQUENCE_EXPRESSION)
@RequestMapping("/sample")
class SingleSegmentedSequenceController(
private val siloQueryModel: SiloQueryModel,
private val requestContext: RequestContext,
Expand Down
4 changes: 2 additions & 2 deletions lapis2/src/test/kotlin/org/genspectrum/lapis/SwaggerUiTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class SwaggerUiTest(
.andExpect(status().isOk)
.andExpect(content().contentType("application/json"))
.andExpect(jsonPath("\$.openapi").exists())
.andExpect(jsonPath("\$.paths./aggregated").exists())
.andExpect(jsonPath("\$.paths./sample/aggregated").exists())
}

@Test
Expand All @@ -47,6 +47,6 @@ class SwaggerUiTest(
val objectMapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
val yaml = objectMapper.readTree(result.response.contentAsString)
assertTrue(yaml.has("openapi"))
assertTrue(yaml.get("paths").has("/aggregated"))
assertTrue(yaml.get("paths").has("/sample/aggregated"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.verify
import org.genspectrum.lapis.controller.AGGREGATED_ROUTE
import org.genspectrum.lapis.controller.getSample
import org.genspectrum.lapis.controller.postSample
import org.genspectrum.lapis.model.SiloQueryModel
import org.genspectrum.lapis.request.LapisInfo
import org.genspectrum.lapis.request.SequenceFiltersRequestWithFields
Expand All @@ -15,7 +17,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
Expand All @@ -24,7 +25,16 @@ private const val NOT_AUTHORIZED_TO_ACCESS_ENDPOINT_ERROR = """
{
"error" : {
"title": "Forbidden",
"detail": "You are not authorized to access /aggregated."
"detail": "You are not authorized to access /sample/aggregated."
}
}
"""

private const val FORBIDDEN_TO_ACCESS_ENDPOINT_ERROR = """
{
"error" : {
"title": "Forbidden",
"detail": "An access key is required to access /sample/aggregated."
}
}
"""
Expand Down Expand Up @@ -55,70 +65,40 @@ class ProtectedDataAuthorizationTest(

@Test
fun `given no access key in GET request to protected instance, then access is denied`() {
mockMvc.perform(get(validRoute))
mockMvc.perform(getSample(validRoute))
.andExpect(status().isForbidden)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
content().json(
"""
{
"error" : {
"title": "Forbidden",
"detail": "An access key is required to access /aggregated."
}
}
""",
),
)
.andExpect(content().json(FORBIDDEN_TO_ACCESS_ENDPOINT_ERROR))
}

@Test
fun `given no access key in POST request to protected instance, then access is denied`() {
mockMvc.perform(postRequestWithBody(""))
.andExpect(status().isForbidden)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
content().json(
"""
{
"error" : {
"title": "Forbidden",
"detail": "An access key is required to access /aggregated."
}
}
""",
),
)
.andExpect(content().json(FORBIDDEN_TO_ACCESS_ENDPOINT_ERROR))
}

@Test
fun `given wrong access key in GET request to protected instance, then access is denied`() {
mockMvc.perform(get("$validRoute?accessKey=invalidKey"))
mockMvc.perform(getSample("$validRoute?accessKey=invalidKey"))
.andExpect(status().isForbidden)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
content().json(
NOT_AUTHORIZED_TO_ACCESS_ENDPOINT_ERROR,
),
)
.andExpect(content().json(NOT_AUTHORIZED_TO_ACCESS_ENDPOINT_ERROR))
}

@Test
fun `given wrong access key in POST request to protected instance, then access is denied`() {
mockMvc.perform(postRequestWithBody("""{"accessKey": "invalidKey"}"""))
.andExpect(status().isForbidden)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
content().json(
NOT_AUTHORIZED_TO_ACCESS_ENDPOINT_ERROR,
),
)
.andExpect(content().json(NOT_AUTHORIZED_TO_ACCESS_ENDPOINT_ERROR))
}

@Test
fun `given valid access key for aggregated data in GET request to protected instance, then access is granted`() {
mockMvc.perform(
get("$validRoute?accessKey=testAggregatedDataAccessKey&field1=value1"),
getSample("$validRoute?accessKey=testAggregatedDataAccessKey&field1=value1"),
)
.andExpect(status().isOk)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand All @@ -145,7 +125,7 @@ class ProtectedDataAuthorizationTest(
@Test
fun `given aggregated access key in GET request but filters are too fine-grained, then access is denied`() {
mockMvc.perform(
get("$validRoute?accessKey=testAggregatedDataAccessKey&gisaid_epi_isl=value"),
getSample("$validRoute?accessKey=testAggregatedDataAccessKey&gisaid_epi_isl=value"),
)
.andExpect(status().isForbidden)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand All @@ -170,7 +150,7 @@ class ProtectedDataAuthorizationTest(
@Test
fun `given valid access key for full access in GET request to protected instance, then access is granted`() {
mockMvc.perform(
get("$validRoute?accessKey=testFullAccessKey&field1=value1"),
getSample("$validRoute?accessKey=testFullAccessKey&field1=value1"),
)
.andExpect(status().isOk)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand Down Expand Up @@ -217,7 +197,7 @@ class ProtectedDataAuthorizationTest(
}

private fun postRequestWithBody(body: String) =
MockMvcRequestBuilders.post(validRoute)
postSample(validRoute)
.contentType(MediaType.APPLICATION_JSON)
.content(body)
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class ExceptionHandlerTest(
fun `throw INTERNAL_SERVER_ERROR(500) with additional info for any non specific error`() {
every { validControllerCall() } throws Exception("SomeMessage")

mockMvc.perform(get(validRoute))
mockMvc.perform(getSample(validRoute))
.andExpect(status().isInternalServerError)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
Expand All @@ -83,7 +83,7 @@ class ExceptionHandlerTest(
fun `Passes through exception with status code from SILO`() {
every { validControllerCall() } throws SiloException(123, "SomeTitle", "SomeMessage")

mockMvc.perform(get(validRoute))
mockMvc.perform(getSample(validRoute))
.andExpect(status().`is`(123))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
Expand All @@ -107,7 +107,7 @@ class ExceptionHandlerTest(
fun `throw BAD_REQUEST(400) with additional info for bad requests`() {
every { validControllerCall() } throws BadRequestException("SomeMessage")

mockMvc.perform(get(validRoute))
mockMvc.perform(getSample(validRoute))
.andExpect(status().isBadRequest)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
Expand All @@ -131,7 +131,7 @@ class ExceptionHandlerTest(
fun `throw NOT_IMPLEMENTED(501) with additional info for request of a not implemented resource in SILO`() {
every { validControllerCall() } throws SiloNotImplementedError("SomeMessage", Exception("SomeCause"))

mockMvc.perform(get(validRoute))
mockMvc.perform(getSample(validRoute))
.andExpect(status().isNotImplemented)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(
Expand Down
Loading

0 comments on commit 60ad1a6

Please sign in to comment.