Tests and refactoring
This commit is contained in:
parent
1c59227030
commit
536ac398c4
17 changed files with 216 additions and 97 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
.idea/
|
||||
|
||||
.env
|
||||
*.tar
|
||||
|
|
8
.idea/.gitignore
vendored
8
.idea/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -1,10 +0,0 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://s01.oss.sonatype.org/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.9.20" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-21" project-jdk-type="JavaSDK" />
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -69,3 +69,7 @@ tasks.named<Test>("test") {
|
|||
// Use JUnit Platform for unit tests.
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
jvmArgs("--add-opens=java.base/java.util=ALL-UNNAMED")
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@ import java.util.concurrent.TimeUnit
|
|||
|
||||
fun main() {
|
||||
val config = Config()
|
||||
val publishers = Publishers(config)
|
||||
val mastodonClientFactory = MastodonClientFactory()
|
||||
val publishers = Publishers(config, mastodonClientFactory)
|
||||
val releaseRepository = ReleaseRepository()
|
||||
val app = App(config, releaseRepository, OkHttpClient(), publishers)
|
||||
app.schedule()
|
||||
|
|
|
@ -49,11 +49,13 @@ class Config {
|
|||
}
|
||||
|
||||
mastodonCredentials = githubRepos.associate {
|
||||
val instanceUrlEnvName = "${it.name.uppercase()}_MASTODON_INSTANCE_URL"
|
||||
val accessTokenEnvName = "${it.name.uppercase()}_MASTODON_ACCESS_TOKEN"
|
||||
it.name to PublishingCredentials(
|
||||
instanceUrlEnvName = "${it.name.uppercase()}_INSTANCE_URL",
|
||||
instanceUrl = System.getenv("${it.name.uppercase()}_INSTANCE_URL"),
|
||||
accessTokenEnvName = "${it.name.uppercase()}_ACCESS_TOKEN",
|
||||
accessToken = System.getenv("${it.name.uppercase()}_ACCESS_TOKEN")
|
||||
instanceUrlEnvName = instanceUrlEnvName,
|
||||
instanceUrl = System.getenv(instanceUrlEnvName),
|
||||
accessTokenEnvName = accessTokenEnvName,
|
||||
accessToken = System.getenv(accessTokenEnvName)
|
||||
)
|
||||
}.onEach { (_, credentials) ->
|
||||
if (!credentials.valid) {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package de.rpr.githubreleases
|
||||
|
||||
import social.bigbone.MastodonClient
|
||||
|
||||
class MastodonClientFactory {
|
||||
fun getClient(url: String, accessToken: String) = MastodonClient.Builder(url)
|
||||
.accessToken(accessToken).build()
|
||||
}
|
|
@ -37,22 +37,29 @@ class Publisher(
|
|||
}
|
||||
}
|
||||
|
||||
class Publishers(private val config: Config) : Iterable<Publisher> {
|
||||
class Publishers(
|
||||
private val config: Config,
|
||||
private val mastodonClientFactory: MastodonClientFactory,
|
||||
) :
|
||||
Iterable<Publisher> {
|
||||
|
||||
private val instances: List<Publisher>
|
||||
|
||||
init {
|
||||
val mastodonClients = config.githubRepos.associate {
|
||||
val publishingCredentials = config.mastodonCredentials[it.name]!!
|
||||
it.name to MastodonClient.Builder(publishingCredentials.instanceUrl!!)
|
||||
.accessToken(publishingCredentials.accessToken!!).build()
|
||||
it.name to mastodonClientFactory.getClient(
|
||||
publishingCredentials.instanceUrl!!,
|
||||
publishingCredentials.accessToken!!
|
||||
)
|
||||
}
|
||||
instances = config.githubRepos.map { Publisher(it.name, mastodonClients[it.name]!!) }
|
||||
}
|
||||
|
||||
fun forName(name: String) = instances.first() { it.name == name }
|
||||
fun forName(name: String) = instances.first { it.name == name }
|
||||
|
||||
override fun iterator(): Iterator<Publisher> {
|
||||
return instances.iterator()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ data class Release(
|
|||
"\uD83C\uDF89 Navidrome $title has been published!\n\nRelease notes are available here: $link\n\n#Navidrome"
|
||||
}
|
||||
|
||||
fun Release.asCollection() = listOf(this).asCollection()
|
||||
fun List<Release>.asCollection() = Releases(this)
|
||||
|
||||
class Releases(releases: List<Release>) : List<Release> {
|
||||
|
|
49
app/src/test/kotlin/de/rpr/githubreleases/ConfigTest.kt
Normal file
49
app/src/test/kotlin/de/rpr/githubreleases/ConfigTest.kt
Normal file
|
@ -0,0 +1,49 @@
|
|||
package de.rpr.githubreleases
|
||||
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.containsExactly
|
||||
import assertk.assertions.containsOnly
|
||||
import io.kotest.core.spec.style.DescribeSpec
|
||||
import io.kotest.extensions.system.withEnvironment
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
|
||||
class ConfigTest : DescribeSpec({
|
||||
|
||||
describe("instantiation") {
|
||||
|
||||
withEnvironment(
|
||||
mapOf(
|
||||
"GITHUB_REPOS" to "https://github.com/navidrome/navidrome/",
|
||||
"NAVIDROME_MASTODON_INSTANCE_URL" to "example.com",
|
||||
"NAVIDROME_MASTODON_ACCESS_TOKEN" to "token"
|
||||
)
|
||||
) {
|
||||
|
||||
it("should populate instances from config") {
|
||||
val config = Config()
|
||||
assertThat(config.githubRepos).containsExactly(
|
||||
GithubRepo("navidrome", "https://github.com/navidrome/navidrome/")
|
||||
)
|
||||
assertThat(config.mastodonCredentials).containsOnly(
|
||||
"navidrome" to Config.PublishingCredentials(
|
||||
instanceUrl = "example.com",
|
||||
accessToken = "token",
|
||||
instanceUrlEnvName = "NAVIDROME_MASTODON_INSTANCE_URL",
|
||||
accessTokenEnvName = "NAVIDROME_MASTODON_ACCESS_TOKEN"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
withEnvironment(
|
||||
mapOf("GITHUB_REPOS" to "https://github.com/navidrome/navidrome/")
|
||||
) {
|
||||
|
||||
it("should throw error if env variables for repo are not present") {
|
||||
assertThrows<IllegalStateException> {
|
||||
Config()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
132
app/src/test/kotlin/de/rpr/githubreleases/PublishersTest.kt
Normal file
132
app/src/test/kotlin/de/rpr/githubreleases/PublishersTest.kt
Normal file
|
@ -0,0 +1,132 @@
|
|||
package de.rpr.githubreleases
|
||||
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isTrue
|
||||
import assertk.assertions.prop
|
||||
import io.kotest.core.spec.style.DescribeSpec
|
||||
import io.kotest.extensions.system.withEnvironment
|
||||
import io.mockk.*
|
||||
import social.bigbone.MastodonClient
|
||||
import social.bigbone.MastodonRequest
|
||||
import social.bigbone.api.entity.Status
|
||||
import social.bigbone.api.entity.data.Visibility
|
||||
import social.bigbone.api.method.StatusMethods
|
||||
|
||||
class PublishersTest : DescribeSpec({
|
||||
|
||||
val mastodonClientFactory = mockk<MastodonClientFactory>()
|
||||
val mastodonClient = mockk<MastodonClient>()
|
||||
|
||||
val statuses = mockk<StatusMethods>(relaxed = true)
|
||||
val mockRequest = mockk<MastodonRequest<Status>>(relaxed = true)
|
||||
|
||||
beforeEach {
|
||||
clearAllMocks()
|
||||
every { mastodonClient.statuses } returns statuses
|
||||
every { mastodonClientFactory.getClient(any(), any()) } returns mastodonClient
|
||||
}
|
||||
|
||||
describe("Publishers collection") {
|
||||
|
||||
withEnvironment(
|
||||
mapOf(
|
||||
"GITHUB_REPOS" to "https://github.com/navidrome/navidrome/",
|
||||
"NAVIDROME_MASTODON_INSTANCE_URL" to "example.com",
|
||||
"NAVIDROME_MASTODON_ACCESS_TOKEN" to "token"
|
||||
)
|
||||
) {
|
||||
|
||||
it("should populate instances from config") {
|
||||
val publishers = Publishers(Config(), mastodonClientFactory)
|
||||
assertThat(publishers.iterator().hasNext()).isTrue()
|
||||
assertThat(publishers.forName("navidrome"))
|
||||
.prop("name") { it.name }
|
||||
.isEqualTo("navidrome")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("Publisher") {
|
||||
|
||||
val publisher = Publisher("example", mastodonClient)
|
||||
|
||||
xit("should send with correct visibility") {
|
||||
|
||||
every {
|
||||
statuses.postStatus(
|
||||
spoilerText = any<String>(),
|
||||
status = any<String>(),
|
||||
language = any<String>(),
|
||||
visibility = any<Visibility>()
|
||||
)
|
||||
} returns mockRequest
|
||||
|
||||
publisher.sendReleases(Releases(testRelease))
|
||||
|
||||
verify {
|
||||
statuses.postStatus(
|
||||
status = any(),
|
||||
mediaIds = any(),
|
||||
visibility = Visibility.PUBLIC,
|
||||
inReplyToId = any(),
|
||||
sensitive = any(),
|
||||
spoilerText = any(),
|
||||
language = "en",
|
||||
addIdempotencyKey = any()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
it("should send correct status text") {
|
||||
every {
|
||||
statuses.postStatus(
|
||||
spoilerText = any<String>(),
|
||||
status = any<String>(),
|
||||
language = any<String>(),
|
||||
visibility = any<Visibility>()
|
||||
)
|
||||
} returns mockRequest
|
||||
|
||||
publisher.sendReleases(testRelease.copy(id = "v0.0.0").asCollection())
|
||||
|
||||
val statusSlot = slot<String>()
|
||||
|
||||
verify {
|
||||
statuses.postStatus(
|
||||
status = capture(statusSlot),
|
||||
mediaIds = any(),
|
||||
visibility = any(),
|
||||
inReplyToId = any(),
|
||||
sensitive = any(),
|
||||
spoilerText = any(),
|
||||
language = any(),
|
||||
addIdempotencyKey = any()
|
||||
)
|
||||
}
|
||||
|
||||
assertThat(statusSlot.captured).isEqualTo("\uD83C\uDF89 Navidrome v0.0.0 has been published!\n\nRelease notes are available here: https://example.com\n\n#Navidrome")
|
||||
}
|
||||
}
|
||||
|
||||
describe("Dry-run mode enabled") {
|
||||
|
||||
val publisher = Publisher(name = "example", client = mastodonClient, dryRun = true)
|
||||
|
||||
it("should not actually send events") {
|
||||
|
||||
every {
|
||||
statuses.postStatus(
|
||||
spoilerText = any<String>(),
|
||||
status = any<String>(),
|
||||
language = any<String>(),
|
||||
visibility = any<Visibility>()
|
||||
)
|
||||
} returns mockRequest
|
||||
|
||||
publisher.sendReleases(testRelease.asCollection())
|
||||
|
||||
verify(exactly = 0) { mockRequest.execute() }
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in a new issue