Add tests
This commit is contained in:
parent
d063ba1c25
commit
8bcc50ea1b
6
pom.xml
6
pom.xml
@ -64,6 +64,12 @@
|
|||||||
<version>5.7.0</version>
|
<version>5.7.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-params</artifactId>
|
||||||
|
<version>5.7.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.assertj</groupId>
|
<groupId>org.assertj</groupId>
|
||||||
<artifactId>assertj-core</artifactId>
|
<artifactId>assertj-core</artifactId>
|
||||||
|
|||||||
@ -32,7 +32,7 @@ data class Project(
|
|||||||
val inputs: List<Input>,
|
val inputs: List<Input>,
|
||||||
val features: List<Feature>,
|
val features: List<Feature>,
|
||||||
val dependencies: List<Dependency>,
|
val dependencies: List<Dependency>,
|
||||||
val repositories: Collection<Repository>,
|
val repositories: Set<Repository>,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Version(val name: String, val value: String)
|
data class Version(val name: String, val value: String)
|
||||||
|
|||||||
@ -2,8 +2,8 @@ package starter.modules
|
|||||||
|
|
||||||
import org.koin.dsl.bind
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import pebble.DepAsXmlPebbleFunction
|
import starter.pebble.DepAsXmlPebbleFunction
|
||||||
import pebble.HasFeatureFilter
|
import starter.pebble.HasFeatureFilter
|
||||||
import starter.utils.PebbleEngineBuilder
|
import starter.utils.PebbleEngineBuilder
|
||||||
import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap
|
import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap
|
||||||
import starter.utils.PebbleFilter
|
import starter.utils.PebbleFilter
|
||||||
|
|||||||
@ -11,10 +11,13 @@ import starter.routes.IndexRouteSupplier
|
|||||||
import starter.routes.RouteSupplier
|
import starter.routes.RouteSupplier
|
||||||
import starter.routes.ZipRouteSupplier
|
import starter.routes.ZipRouteSupplier
|
||||||
import starter.routes.toRouter
|
import starter.routes.toRouter
|
||||||
|
import starter.utils.ProjectExtractor
|
||||||
|
import starter.utils.ProjectExtractorImpl
|
||||||
|
|
||||||
val routesModule = module {
|
val routesModule = module {
|
||||||
single { IndexRouteSupplier(get()) } bind RouteSupplier::class
|
single { IndexRouteSupplier(get()) } bind RouteSupplier::class
|
||||||
single { ZipRouteSupplier(get(), get()) } bind RouteSupplier::class
|
single { ZipRouteSupplier(get(), get()) } bind RouteSupplier::class
|
||||||
|
single<ProjectExtractor> { ProjectExtractorImpl(get()) }
|
||||||
single {
|
single {
|
||||||
ServerFilters.CatchAll().then(
|
ServerFilters.CatchAll().then(
|
||||||
routes(
|
routes(
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package pebble
|
package starter.pebble
|
||||||
|
|
||||||
import com.mitchellbosecke.pebble.extension.escaper.SafeString
|
import com.mitchellbosecke.pebble.extension.escaper.SafeString
|
||||||
import com.mitchellbosecke.pebble.template.EvaluationContext
|
import com.mitchellbosecke.pebble.template.EvaluationContext
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package pebble
|
package starter.pebble
|
||||||
|
|
||||||
import com.mitchellbosecke.pebble.template.EvaluationContext
|
import com.mitchellbosecke.pebble.template.EvaluationContext
|
||||||
import com.mitchellbosecke.pebble.template.PebbleTemplate
|
import com.mitchellbosecke.pebble.template.PebbleTemplate
|
||||||
@ -1,62 +1,35 @@
|
|||||||
package starter.routes
|
package starter.routes
|
||||||
|
|
||||||
import org.http4k.core.Method
|
import org.http4k.core.Method
|
||||||
|
import org.http4k.core.Request
|
||||||
import org.http4k.core.Response
|
import org.http4k.core.Response
|
||||||
import org.http4k.core.body.form
|
|
||||||
import org.http4k.core.body.formAsMap
|
|
||||||
import org.http4k.core.with
|
import org.http4k.core.with
|
||||||
import org.http4k.routing.bind
|
import org.http4k.routing.bind
|
||||||
import starter.Project
|
|
||||||
import starter.ProjectZip
|
import starter.ProjectZip
|
||||||
import starter.config.StarterConfig
|
|
||||||
import starter.extensions.attachment
|
import starter.extensions.attachment
|
||||||
import starter.extensions.badRequest
|
import starter.extensions.badRequest
|
||||||
import starter.extensions.ok
|
import starter.extensions.ok
|
||||||
|
import starter.utils.ProjectExtractor
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
class ZipRouteSupplier(
|
class ZipRouteSupplier(
|
||||||
private val conf: StarterConfig,
|
private val projectExtractor: ProjectExtractor,
|
||||||
private val projectZip: ProjectZip,
|
private val projectZip: ProjectZip,
|
||||||
) : RouteSupplier {
|
) : RouteSupplier {
|
||||||
|
|
||||||
override fun get() = "/" bind Method.POST to { req ->
|
private fun handle(req: Request): Response {
|
||||||
|
val project = projectExtractor(req) ?: return Response.badRequest()
|
||||||
|
|
||||||
val deps = conf.dependencies.filter {
|
val outputStream = projectZip.createZip(project)
|
||||||
req.form(it.name) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
val formMap = req.formAsMap()
|
return Response.ok().with(
|
||||||
|
attachment(
|
||||||
val inputKeys = conf.inputs.map { it.name }
|
value = ByteArrayInputStream(outputStream.toByteArray()),
|
||||||
val inputs = formMap
|
name = "${project.name}.zip",
|
||||||
.filter { it.key in inputKeys }
|
contentType = "application/zip"
|
||||||
.map { (name, value) ->
|
|
||||||
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
|
||||||
}
|
|
||||||
|
|
||||||
val features = formMap
|
|
||||||
.filter { it.key in conf.features.map { it.name } }
|
|
||||||
.map { (name, _) ->
|
|
||||||
conf.features.find { it.name == name }!!.copy(value = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val projectName = inputs.find { it.name == "name" }!!.value!!
|
|
||||||
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
|
|
||||||
|
|
||||||
if (basePackage.contains("/") || basePackage.contains("..")) {
|
|
||||||
Response.badRequest()
|
|
||||||
} else {
|
|
||||||
val repositories = deps.mapNotNull { it.repository }.toSet()
|
|
||||||
val project = Project(projectName, basePackage, inputs, features, deps, repositories)
|
|
||||||
val outputStream = projectZip.createZip(project)
|
|
||||||
|
|
||||||
Response.ok().with(
|
|
||||||
attachment(
|
|
||||||
value = ByteArrayInputStream(outputStream.toByteArray()),
|
|
||||||
name = "$projectName.zip",
|
|
||||||
contentType = "application/zip"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun get() = "/" bind Method.POST to ::handle
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,6 @@ class PomTemplate(private val engine: PebbleEngine) : Template {
|
|||||||
args[it.name] = it.value
|
args[it.name] = it.value
|
||||||
}
|
}
|
||||||
|
|
||||||
println(args.entries.joinToString("\n"))
|
|
||||||
|
|
||||||
val rendered = engine.render("starter/pom/index", args)
|
val rendered = engine.render("starter/pom/index", args)
|
||||||
return prettyPrintXml(rendered)
|
return prettyPrintXml(rendered)
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/main/kotlin/starter/utils/ProjectExtractor.kt
Normal file
44
src/main/kotlin/starter/utils/ProjectExtractor.kt
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package starter.utils
|
||||||
|
|
||||||
|
import org.http4k.core.Request
|
||||||
|
import org.http4k.core.body.form
|
||||||
|
import org.http4k.core.body.formAsMap
|
||||||
|
import starter.Project
|
||||||
|
import starter.config.StarterConfig
|
||||||
|
|
||||||
|
interface ProjectExtractor {
|
||||||
|
operator fun invoke(request: Request): Project?
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectExtractorImpl(private val conf: StarterConfig) : ProjectExtractor {
|
||||||
|
override fun invoke(request: Request): Project? {
|
||||||
|
val deps = conf.dependencies.filter {
|
||||||
|
request.form(it.name) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
val formMap = request.formAsMap()
|
||||||
|
|
||||||
|
val inputKeys = conf.inputs.map { it.name }
|
||||||
|
val inputs = formMap
|
||||||
|
.filter { it.key in inputKeys }
|
||||||
|
.map { (name, value) ->
|
||||||
|
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
||||||
|
}
|
||||||
|
|
||||||
|
val features = formMap
|
||||||
|
.filter { it.key in conf.features.map { it.name } }
|
||||||
|
.map { (name, _) ->
|
||||||
|
conf.features.find { it.name == name }!!.copy(value = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val projectName = inputs.find { it.name == "name" }?.value ?: return null
|
||||||
|
val basePackage = inputs.find { it.name == "basePackage" }?.value ?: return null
|
||||||
|
|
||||||
|
return if (basePackage.contains("/") || basePackage.contains("..")) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
val repositories = deps.mapNotNull { it.repository }.toSet()
|
||||||
|
Project(projectName, basePackage, inputs, features, deps, repositories)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/test/kotlin/starter/TestProject.kt
Normal file
46
src/test/kotlin/starter/TestProject.kt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package starter
|
||||||
|
|
||||||
|
import starter.config.StarterConfig
|
||||||
|
|
||||||
|
val testConfig = StarterConfig(
|
||||||
|
dependencies = listOf(
|
||||||
|
Dependency(
|
||||||
|
name = "h2",
|
||||||
|
groupId = "com.h2database",
|
||||||
|
artifactId = "h2",
|
||||||
|
version = Version("h2", "1.4.200"),
|
||||||
|
default = false,
|
||||||
|
category = Category.Database,
|
||||||
|
scope = Scope.Compile,
|
||||||
|
logger = null,
|
||||||
|
repository = null,
|
||||||
|
),
|
||||||
|
Dependency(
|
||||||
|
name = "assertj",
|
||||||
|
groupId = "org.assertj",
|
||||||
|
artifactId = "assertj-core",
|
||||||
|
version = Version("assertj", "3.17.2"),
|
||||||
|
default = true,
|
||||||
|
category = Category.Test,
|
||||||
|
scope = Scope.Test,
|
||||||
|
logger = null,
|
||||||
|
repository = null,
|
||||||
|
),
|
||||||
|
Dependency(
|
||||||
|
name = "koin",
|
||||||
|
groupId = "org.koin",
|
||||||
|
artifactId = "koin-core",
|
||||||
|
version = Version("koin", "2.1.6"),
|
||||||
|
default = true,
|
||||||
|
category = Category.Injection,
|
||||||
|
scope = Scope.Compile,
|
||||||
|
logger = null,
|
||||||
|
repository = Repository("jcenter", "https://jcenter.bintray.com"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
inputs = listOf(
|
||||||
|
Input(name = "name", display = "name", value = "example"),
|
||||||
|
Input(name = "basePackage", display = "Base package", value = "org.example"),
|
||||||
|
),
|
||||||
|
features = listOf(Feature("ktlint", true))
|
||||||
|
)
|
||||||
109
src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt
Normal file
109
src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package starter.utils
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.http4k.core.Method
|
||||||
|
import org.http4k.core.Request
|
||||||
|
import org.http4k.core.body.Form
|
||||||
|
import org.http4k.core.body.toBody
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource
|
||||||
|
import org.koin.dsl.koinApplication
|
||||||
|
import org.koin.dsl.module
|
||||||
|
import starter.Feature
|
||||||
|
import starter.Input
|
||||||
|
import starter.Project
|
||||||
|
import starter.modules.routesModule
|
||||||
|
import starter.testConfig
|
||||||
|
import java.util.stream.Stream
|
||||||
|
|
||||||
|
internal class ProjectExtractorImplTest {
|
||||||
|
|
||||||
|
private val fakeModule = module {
|
||||||
|
single { testConfig }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val koin = koinApplication {
|
||||||
|
modules(routesModule, fakeModule)
|
||||||
|
}.koin
|
||||||
|
|
||||||
|
private val projectExtractor = koin.get<ProjectExtractor>()
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
fun invalidProjectsSource(): Stream<Form> = Stream.of(
|
||||||
|
emptyList(),
|
||||||
|
listOf(
|
||||||
|
"basePackage" to "org.example",
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
"basePackage" to "org.example/a",
|
||||||
|
"name" to "test"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidProjectsSource")
|
||||||
|
fun invalidProjects(form: Form) {
|
||||||
|
val request = Request(Method.POST, "")
|
||||||
|
.body(form.toBody())
|
||||||
|
|
||||||
|
val project = projectExtractor(request)
|
||||||
|
|
||||||
|
assertThat(project).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
fun validProjectsSource(): Stream<Pair<Form, Project>> = Stream.of(
|
||||||
|
listOf(
|
||||||
|
"name" to "Test",
|
||||||
|
"basePackage" to "org.example",
|
||||||
|
"ktlint" to "",
|
||||||
|
) to Project(
|
||||||
|
name = "Test",
|
||||||
|
basePackage = "org.example",
|
||||||
|
inputs = listOf(
|
||||||
|
Input(name = "name", display = "name", value = "Test"),
|
||||||
|
Input(name = "basePackage", display = "Base package", value = "org.example"),
|
||||||
|
),
|
||||||
|
features = listOf(
|
||||||
|
Feature(name = "ktlint", value = true)
|
||||||
|
),
|
||||||
|
dependencies = listOf(),
|
||||||
|
repositories = setOf(),
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
"name" to "Test",
|
||||||
|
"basePackage" to "org.example",
|
||||||
|
"ktlint" to "",
|
||||||
|
"koin" to "",
|
||||||
|
) to Project(
|
||||||
|
name = "Test",
|
||||||
|
basePackage = "org.example",
|
||||||
|
inputs = listOf(
|
||||||
|
Input(name = "name", display = "name", value = "Test"),
|
||||||
|
Input(name = "basePackage", display = "Base package", value = "org.example"),
|
||||||
|
),
|
||||||
|
features = listOf(
|
||||||
|
Feature(name = "ktlint", value = true)
|
||||||
|
),
|
||||||
|
dependencies = listOf(
|
||||||
|
testConfig.dependencies.find { it.name == "koin" }!!
|
||||||
|
),
|
||||||
|
repositories = setOf(
|
||||||
|
testConfig.dependencies.find { it.name == "koin" }!!.repository!!
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("validProjectsSource")
|
||||||
|
fun validProjects(pair: Pair<Form, Project>) {
|
||||||
|
val (form, expected) = pair
|
||||||
|
|
||||||
|
val request = Request(Method.POST, "")
|
||||||
|
.body(form.toBody())
|
||||||
|
|
||||||
|
val project = projectExtractor(request)
|
||||||
|
|
||||||
|
assertThat(project).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/test/resources/junit-platform.properties
Normal file
4
src/test/resources/junit-platform.properties
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
junit.jupiter.testinstance.lifecycle.default=per_class
|
||||||
|
junit.jupiter.execution.parallel.enabled=true
|
||||||
|
junit.jupiter.execution.parallel.mode.default=same_thread
|
||||||
|
junit.jupiter.execution.parallel.mode.classes.default=concurrent
|
||||||
Loading…
x
Reference in New Issue
Block a user