Skip to content
This repository was archived by the owner on Oct 14, 2021. It is now read-only.
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import net.adoptopenjdk.api.v3.models.ImageType
import net.adoptopenjdk.api.v3.models.JvmImpl
import net.adoptopenjdk.api.v3.models.OperatingSystem
import net.adoptopenjdk.api.v3.models.Project
import java.time.ZonedDateTime
import java.util.function.Predicate

class BinaryFilter : Predicate<Binary> {
Expand All @@ -17,21 +18,24 @@ class BinaryFilter : Predicate<Binary> {
private val jvmImpl: JvmImpl?
private val heapSize: HeapSize?
private val project: Project
private var before: ZonedDateTime?

constructor(
os: OperatingSystem?,
arch: Architecture?,
imageType: ImageType?,
jvmImpl: JvmImpl?,
heapSize: HeapSize?,
project: Project?
os: OperatingSystem? = null,
arch: Architecture? = null,
imageType: ImageType? = null,
jvmImpl: JvmImpl? = null,
heapSize: HeapSize? = null,
project: Project? = null,
before: ZonedDateTime? = null
) {
this.os = os
this.arch = arch
this.imageType = imageType
this.jvmImpl = jvmImpl
this.heapSize = heapSize
this.project = project ?: Project.jdk
this.before = before
}

override fun test(binary: Binary): Boolean {
Expand All @@ -40,6 +44,7 @@ class BinaryFilter : Predicate<Binary> {
(imageType == null || binary.image_type == imageType) &&
(jvmImpl == null || binary.jvm_impl == jvmImpl) &&
(heapSize == null || binary.heap_size == heapSize) &&
(binary.project == project)
(binary.project == project) &&
(before == null || binary.updated_at.isBefore(before))
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.adoptopenjdk.api.v3.routes

import net.adoptopenjdk.api.v3.OpenApiDocs
import net.adoptopenjdk.api.v3.TimeSource
import net.adoptopenjdk.api.v3.dataSources.APIDataStore
import net.adoptopenjdk.api.v3.dataSources.SortOrder
import net.adoptopenjdk.api.v3.filters.BinaryFilter
Expand All @@ -26,6 +27,14 @@ import org.eclipse.microprofile.openapi.annotations.responses.APIResponses
import org.eclipse.microprofile.openapi.annotations.tags.Tag
import org.jboss.resteasy.annotations.jaxrs.PathParam
import org.jboss.resteasy.annotations.jaxrs.QueryParam
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.OffsetDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
import java.time.temporal.TemporalQuery
import javax.ws.rs.BadRequestException
import javax.ws.rs.GET
import javax.ws.rs.NotFoundException
import javax.ws.rs.Path
Expand Down Expand Up @@ -92,6 +101,16 @@ class AssetsResource {
@QueryParam("project")
project: Project?,

@Parameter(
name = "before",
description = "Return binaries whose updated_at is before the given date/time. When a date is given the match is inclusive of the given day.",
schema = Schema(type = SchemaType.STRING),
example = "2020-01-21, 2020-01-21T10:15:30, 20200121, 2020-12-21T10:15:30Z, 2020-12-21+01:00",
required = false
)
@QueryParam("before")
before: String?,

@Parameter(name = "page_size", description = "Pagination page size",
schema = Schema(defaultValue = "10", type = SchemaType.INTEGER), required = false
)
Expand All @@ -111,8 +130,10 @@ class AssetsResource {
): List<Release> {
val order = sortOrder ?: SortOrder.DESC

val beforeParsed = parseDate(before)

val releaseFilter = ReleaseFilter(releaseType = release_type, featureVersion = version, vendor = vendor)
val binaryFilter = BinaryFilter(os, arch, image_type, jvm_impl, heap_size, project)
val binaryFilter = BinaryFilter(os, arch, image_type, jvm_impl, heap_size, project, beforeParsed)
val repos = APIDataStore.getAdoptRepos().getFeatureRelease(version!!)

if (repos == null) {
Expand All @@ -126,6 +147,43 @@ class AssetsResource {
return getPage(pageSize, page, releases)
}

private fun parseDate(before: String?): ZonedDateTime? {
return if (before != null) {
try {
val date = LocalDate.parse(before, DateTimeFormatter.ISO_DATE)
return date.plusDays(1).atStartOfDay(TimeSource.ZONE)
} catch (e: DateTimeParseException) {
// NOP
}

try {
val date = DateTimeFormatter.ISO_DATE_TIME.parseBest(before,
TemporalQuery { p0 -> ZonedDateTime.from(p0) },
TemporalQuery { p0 -> OffsetDateTime.from(p0) },
TemporalQuery { p0 -> LocalDateTime.from(p0) }
)

return when (date) {
is LocalDateTime -> date.atZone(TimeSource.ZONE)
is OffsetDateTime -> date.atZoneSameInstant(TimeSource.ZONE)
is ZonedDateTime -> date
else -> null
}
} catch (e: DateTimeParseException) {
// NOP
}

try {
val date = LocalDate.parse(before, DateTimeFormatter.BASIC_ISO_DATE)
return date.plusDays(1).atStartOfDay(TimeSource.ZONE)
} catch (e: DateTimeParseException) {
throw BadRequestException("Cannot parse date")
}
} else {
null
}
}

@GET
@Path("/version/{version}")
@Operation(summary = "Returns release information about the specified version.",
Expand Down Expand Up @@ -201,12 +259,10 @@ class AssetsResource {
): List<Release> {
val order = sortOrder ?: SortOrder.DESC

// Require GA due to version range having no meaning for nightlies

val range = VersionRangeFilter(version)

val releaseFilter = ReleaseFilter(releaseType = release_type, vendor = vendor, versionRange = range, lts = lts)
val binaryFilter = BinaryFilter(os, arch, image_type, jvm_impl, heap_size, project)
val binaryFilter = BinaryFilter(os = os, arch = arch, imageType = image_type, jvmImpl = jvm_impl, heapSize = heap_size, project = project)

val releases = APIDataStore
.getAdoptRepos()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,98 +22,98 @@ class AssetsResourceFeatureReleasePathTest : AssetsPathTest() {
@TestFactory
fun noFilter(): Stream<DynamicTest> {
return (8..12)
.flatMap { version ->
ReleaseType.values()
.map { "/v3/assets/feature_releases/$version/$it" }
.map {
DynamicTest.dynamicTest(it) {
RestAssured.given()
.`when`()
.get(it)
.then()
.statusCode(200)
}
}
}
.stream()
.flatMap { version ->
ReleaseType.values()
.map { "/v3/assets/feature_releases/$version/$it" }
.map {
DynamicTest.dynamicTest(it) {
RestAssured.given()
.`when`()
.get(it)
.then()
.statusCode(200)
}
}
}
.stream()
}

@Test
fun badReleaseType() {
RestAssured.given()
.`when`()
.get("${getPath()}/8/foo")
.then()
.statusCode(404)
.`when`()
.get("${getPath()}/8/foo")
.then()
.statusCode(404)
}

@Test
fun badVersion() {
RestAssured.given()
.`when`()
.get("2/${getPath()}")
.then()
.statusCode(404)
.`when`()
.get("2/${getPath()}")
.then()
.statusCode(404)
}

@Test
fun sortOrderASCIsHonoured() {
getReleases(SortOrder.ASC)
.fold(null, { previous: Release?, next: Release ->
if (previous != null) {
if (Releases.VERSION_COMPARATOR.compare(previous, next) > 0) {
fail("${previous.version_data} is before ${next.version_data}")
}
.fold(null, { previous: Release?, next: Release ->
if (previous != null) {
if (Releases.VERSION_COMPARATOR.compare(previous, next) > 0) {
fail("${previous.version_data} is before ${next.version_data}")
}
next
})
}
next
})
}

@Test
fun sortOrderDESIsHonoured() {
getReleases(SortOrder.DESC)
.fold(null, { previous: Release?, next: Release ->
if (previous != null) {
if (Releases.VERSION_COMPARATOR.compare(previous, next) < 0) {
fail("${previous.version_data} is before ${next.version_data}")
}
.fold(null, { previous: Release?, next: Release ->
if (previous != null) {
if (Releases.VERSION_COMPARATOR.compare(previous, next) < 0) {
fail("${previous.version_data} is before ${next.version_data}")
}
next
})
}
next
})
}

override fun <T> runFilterTest(filterParamName: String, values: Array<T>): Stream<DynamicTest> {
return ReleaseType.values()
.flatMap { releaseType ->
// test the ltses and 1 non-lts
listOf(8, 11, 12)
.flatMap { version ->
createTest(values, "${getPath()}/$version/$releaseType", filterParamName, { element ->
getExclusions(version, element)
})
}
}
.stream()
.flatMap { releaseType ->
// test the ltses and 1 non-lts
listOf(8, 11, 12)
.flatMap { version ->
createTest(values, "${getPath()}/$version/$releaseType", filterParamName, { element ->
getExclusions(version, element)
})
}
}
.stream()
}

private fun <T> getExclusions(version: Int, element: T): Boolean {
return version == 11 && element == OperatingSystem.solaris ||
version == 12 && element == OperatingSystem.solaris ||
version == 8 && element == Architecture.arm ||
version != 8 && element == Architecture.sparcv9 ||
version == 8 && element == ImageType.testimage ||
version == 11 && element == ImageType.testimage ||
version == 12 && element == ImageType.testimage ||
element == ImageType.debugimage
version == 12 && element == OperatingSystem.solaris ||
version == 8 && element == Architecture.arm ||
version != 8 && element == Architecture.sparcv9 ||
version == 8 && element == ImageType.testimage ||
version == 11 && element == ImageType.testimage ||
version == 12 && element == ImageType.testimage ||
element == ImageType.debugimage
}

companion object {
fun getPath() = "/v3/assets/feature_releases"
fun getReleases(sortOrder: SortOrder): List<Release> {
val body = RestAssured.given()
.`when`()
.get("${getPath()}/8/ga?sort_order=${sortOrder.name}")
.body
.`when`()
.get("${getPath()}/8/ga?sort_order=${sortOrder.name}")
.body

val releasesStr = body.prettyPrint()
return JsonMapper.mapper.readValue(releasesStr, JsonMapper.mapper.getTypeFactory().constructCollectionType(MutableList::class.java, Release::class.java))
Expand All @@ -122,11 +122,39 @@ class AssetsResourceFeatureReleasePathTest : AssetsPathTest() {

@Test
fun pagination() {

RestAssured.given()
.`when`()
.get("${getPath()}/8/ga?pageSize=1&page=1")
.then()
.statusCode(200)
.`when`()
.get("${getPath()}/8/ga?pageSize=1&page=1")
.then()
.statusCode(200)
}

@TestFactory
fun beforeFilter(): Stream<DynamicTest> {
return listOf(
Pair("2099-01-01", 200),
Pair("2099-01-01T10:15:30", 200),
Pair("20990101", 200),
Pair("2099-12-03T10:15:30Z", 200),
Pair("2099-12-03+01:00", 200),

Pair("2000-01-01", 404),
Pair("2000-01-01T10:15:30", 404),
Pair("20000101", 404),
Pair("2000-12-03T10:15:30Z", 404),
Pair("2000-12-03+01:00", 404),

Pair("foo", 400)
)
.map {
DynamicTest.dynamicTest(it.first) {
RestAssured.given()
.`when`()
.get("${getPath()}/11/ea?before=${it.first}")
.then()
.statusCode(it.second)
}
}
.stream()
}
}