Skip to content

Commit 001526a

Browse files
committed
Add tests for GMavenService
1 parent da0dbdc commit 001526a

File tree

5 files changed

+503
-0
lines changed

5 files changed

+503
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.google.firebase.gradle
2+
3+
import io.mockk.MockKMatcherScope
4+
import java.io.File
5+
import org.gradle.testkit.runner.BuildResult
6+
import org.gradle.testkit.runner.GradleRunner
7+
8+
/**
9+
* Create a [GradleRunner] and run it.
10+
*
11+
* @param directory The project directory to run gradle from
12+
* @param arguments Task arguments to pass to gradle
13+
* @see createGradleRunner
14+
*/
15+
fun runGradle(directory: File, vararg arguments: String): BuildResult =
16+
createGradleRunner(directory, *arguments).build()
17+
18+
/**
19+
* Creates a [GradleRunner], with preconfigured values for tests.
20+
*
21+
* @param directory The project directory to run gradle from
22+
* @param arguments Task arguments to pass to gradle
23+
* @see runGradle
24+
*/
25+
fun createGradleRunner(directory: File, vararg arguments: String): GradleRunner =
26+
GradleRunner.create()
27+
.withProjectDir(directory)
28+
.withPluginClasspath()
29+
.forwardOutput()
30+
.withArguments(
31+
*arguments,
32+
"--stacktrace",
33+
"-Dorg.gradle.kotlin.dsl.scriptCompilationAvoidance=false",
34+
)
35+
36+
/** Match arguments that end with the specified [str]. */
37+
fun MockKMatcherScope.endsWith(str: String) = match<String> { it.endsWith(str) }
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
package com.google.firebase.gradle.services
2+
3+
import com.google.firebase.gradle.endsWith
4+
import com.google.firebase.gradle.plugins.childFile
5+
import com.google.firebase.gradle.plugins.services.DocumentService
6+
import com.google.firebase.gradle.plugins.services.GMavenServiceController
7+
import io.kotest.assertions.asClue
8+
import io.kotest.core.spec.style.FunSpec
9+
import io.kotest.inspectors.forAll
10+
import io.kotest.matchers.collections.shouldContain
11+
import io.kotest.matchers.collections.shouldNotBeEmpty
12+
import io.kotest.matchers.equals.shouldBeEqual
13+
import io.kotest.matchers.equals.shouldNotBeEqual
14+
import io.kotest.matchers.file.shouldExist
15+
import io.kotest.matchers.file.shouldHaveSameContentAs
16+
import io.kotest.matchers.nulls.shouldBeNull
17+
import io.kotest.matchers.nulls.shouldNotBeNull
18+
import io.kotest.matchers.shouldBe
19+
import io.mockk.clearMocks
20+
import io.mockk.every
21+
import io.mockk.spyk
22+
import io.mockk.verify
23+
import java.io.File
24+
import java.io.FileNotFoundException
25+
import java.util.concurrent.ExecutorService
26+
import java.util.concurrent.Executors
27+
import java.util.concurrent.TimeUnit
28+
import org.junit.Before
29+
import org.junit.Rule
30+
import org.junit.Test
31+
import org.junit.rules.TemporaryFolder
32+
33+
class GMavenServiceTests : FunSpec() {
34+
@Rule @JvmField val testProjectDir = TemporaryFolder()
35+
private val service = spyk(DocumentService())
36+
private val gmaven by lazy { GMavenServiceController(testProjectDir.root.toPath(), service) }
37+
38+
@Before
39+
fun setup() {
40+
clearMocks(service)
41+
42+
every { service.openStream(any()) } throws (FileNotFoundException())
43+
every { service.openStream(endsWith("group-index.xml")) } answers
44+
{
45+
testGroupIndex.inputStream()
46+
}
47+
}
48+
49+
@Test
50+
fun `fetches group index`() {
51+
val artifacts = gmaven.forceGetGroupIndex("com.google.firebase")
52+
verify { service.openStream(endsWith("group-index.xml")) }
53+
54+
artifacts.shouldNotBeEmpty()
55+
56+
val artifact = artifacts.find { it.artifactId == "firebase-common" }
57+
58+
artifact.shouldNotBeNull()
59+
artifact.asClue {
60+
it.versions.shouldContain("21.0.0")
61+
it.latestVersion shouldBeEqual "21.0.0"
62+
}
63+
}
64+
65+
@Test
66+
fun `fetches a released pom file`() {
67+
every { service.openStream(endsWith("firebase-common-21.0.0.pom")) } answers
68+
{
69+
testPOM.inputStream()
70+
}
71+
72+
val pomElement = gmaven.pomOrNull("com.google.firebase", "firebase-common", "21.0.0")
73+
74+
verify { service.openStream(endsWith("firebase-common-21.0.0.pom")) }
75+
76+
pomElement.shouldNotBeNull()
77+
pomElement.asClue {
78+
it.version shouldBe "21.0.0"
79+
it.artifactId shouldBe "firebase-common"
80+
it.packaging shouldBe "aar"
81+
it.dependencies.shouldNotBeEmpty()
82+
}
83+
}
84+
85+
@Test
86+
fun `fetches a released aar file`() {
87+
every { service.openStream(endsWith("firebase-common-21.0.0.aar")) } answers
88+
{
89+
testAAR.inputStream()
90+
}
91+
92+
val aar = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0")
93+
94+
verify { service.openStream(endsWith("firebase-common-21.0.0.aar")) }
95+
96+
aar.shouldNotBeNull()
97+
aar.shouldExist()
98+
aar.shouldHaveSameContentAs(testAAR)
99+
}
100+
101+
@Test
102+
fun `fetches a released jar file`() {
103+
every { service.openStream(endsWith("firebase-common-21.0.0.jar")) } answers
104+
{
105+
testAAR.inputStream()
106+
}
107+
108+
val jar = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0")
109+
110+
verify { service.openStream(endsWith("firebase-common-21.0.0.jar")) }
111+
112+
jar.shouldNotBeNull()
113+
jar.shouldExist()
114+
jar.shouldHaveSameContentAs(testAAR)
115+
}
116+
117+
@Test
118+
fun `returns null when artifact files are not found`() {
119+
val artifact = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0")
120+
121+
verify { service.openStream(endsWith("firebase-common-21.0.0.aar")) }
122+
123+
artifact.shouldBeNull()
124+
}
125+
126+
@Test
127+
fun `fetches the latest released version`() {
128+
val version = gmaven.latestVersionOrNull("com.google.firebase", "firebase-common")
129+
130+
verify(exactly = 1) { service.openStream(any()) }
131+
132+
version.shouldNotBeNull()
133+
version shouldBeEqual "21.0.0"
134+
}
135+
136+
@Test
137+
fun `checks if an artifact has been published`() {
138+
gmaven.hasReleasedArtifact("com.google.firebase", "artifact-that-doesnt-exist") shouldBe false
139+
gmaven.hasReleasedArtifact("com.google.firebase", "firebase-common") shouldBe true
140+
141+
verify(exactly = 1) { service.openStream(any()) }
142+
}
143+
144+
@Test
145+
fun `checks if a version has been released`() {
146+
gmaven.hasReleasedVersion("com.google.firebase", "firebase-common", "21.0.0") shouldBe true
147+
gmaven.hasReleasedVersion("com.google.firebase", "firebase-common", "22.0.0") shouldBe false
148+
149+
verify(exactly = 1) { service.openStream(any()) }
150+
}
151+
152+
@Test
153+
fun `caches pom requests`() {
154+
every { service.openStream(endsWith("firebase-common-21.0.0.pom")) } answers
155+
{
156+
testPOM.inputStream()
157+
}
158+
159+
val firstPom = gmaven.pomOrNull("com.google.firebase", "firebase-common", "21.0.0")
160+
val secondPom = gmaven.pomOrNull("com.google.firebase", "firebase-common", "21.0.0")
161+
162+
verify(exactly = 1) { service.openStream(endsWith("firebase-common-21.0.0.pom")) }
163+
164+
firstPom.shouldNotBeNull()
165+
secondPom.shouldNotBeNull()
166+
167+
firstPom.shouldBeEqual(secondPom)
168+
}
169+
170+
@Test
171+
fun `caches artifact requests`() {
172+
every { service.openStream(endsWith("firebase-common-21.0.0.aar")) } answers
173+
{
174+
testAAR.inputStream()
175+
}
176+
177+
val firstArtifact = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0")
178+
val secondArtifact = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0")
179+
180+
verify(exactly = 1) { service.openStream(endsWith("firebase-common-21.0.0.aar")) }
181+
182+
firstArtifact.shouldNotBeNull()
183+
secondArtifact.shouldNotBeNull()
184+
185+
firstArtifact.shouldBeEqual(secondArtifact)
186+
}
187+
188+
@Test
189+
fun `does not overwrite previous force fetches`() {
190+
every { service.openStream(endsWith("firebase-common-21.0.0.aar")) } answers
191+
{
192+
testAAR.inputStream()
193+
}
194+
195+
val firstArtifact = gmaven.forceGetArtifact("com.google.firebase", "firebase-common", "21.0.0")
196+
val secondArtifact = gmaven.forceGetArtifact("com.google.firebase", "firebase-common", "21.0.0")
197+
198+
verify(exactly = 2) { service.openStream(endsWith("firebase-common-21.0.0.aar")) }
199+
200+
firstArtifact.shouldNotBeNull()
201+
secondArtifact.shouldNotBeNull()
202+
203+
firstArtifact.shouldExist()
204+
secondArtifact.shouldExist()
205+
206+
firstArtifact.shouldNotBeEqual(secondArtifact)
207+
}
208+
209+
@Test
210+
fun `should be thread safe`() {
211+
every { service.openStream(endsWith("firebase-common-21.0.0.aar")) } answers
212+
{
213+
testAAR.inputStream()
214+
}
215+
216+
every { service.openStream(endsWith("firebase-common-20.0.0.aar")) } answers
217+
{
218+
testAAR.inputStream()
219+
}
220+
221+
val executor = Executors.newFixedThreadPool(10)
222+
223+
val firstBatch =
224+
(0 until 100).map {
225+
executor.queue { gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0") }
226+
}
227+
228+
val secondBatch =
229+
(0 until 100).map {
230+
executor.queue { gmaven.artifactOrNull("com.google.firebase", "firebase-common", "20.0.0") }
231+
}
232+
233+
verify(exactly = 0) { service.openStream(any()) }
234+
235+
executor.shutdown()
236+
executor.awaitTermination(5, TimeUnit.SECONDS)
237+
238+
verify(exactly = 3) { service.openStream(any()) }
239+
240+
val firstArtifact = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "21.0.0")
241+
val secondArtifact = gmaven.artifactOrNull("com.google.firebase", "firebase-common", "20.0.0")
242+
243+
firstArtifact.shouldNotBeNull()
244+
secondArtifact.shouldNotBeNull()
245+
246+
firstBatch.forAll {
247+
it.isDone shouldBe true
248+
firstArtifact.shouldBeEqual(it.get().shouldNotBeNull())
249+
}
250+
251+
secondBatch.forAll {
252+
it.isDone shouldBe true
253+
secondArtifact.shouldBeEqual(it.get().shouldNotBeNull())
254+
}
255+
}
256+
257+
@Suppress("ControlFlowWithEmptyBody")
258+
private fun <T> ExecutorService.queue(task: () -> T) =
259+
submit<T> {
260+
while (!isShutdown) {}
261+
task()
262+
}
263+
264+
companion object {
265+
private val resourcesDirectory = File("src/test/resources")
266+
private val testResources = resourcesDirectory.childFile("GMaven")
267+
private val testAAR = testResources.childFile("firebase-common.aar")
268+
private val testPOM = testResources.childFile("firebase-common.pom")
269+
private val testGroupIndex = testResources.childFile("group-index.xml")
270+
}
271+
}
113 KB
Binary file not shown.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>com.google.firebase</groupId>
5+
<artifactId>firebase-common</artifactId>
6+
<version>21.0.0</version>
7+
<packaging>aar</packaging>
8+
<licenses>
9+
<license>
10+
<name>The Apache Software License, Version 2.0</name>
11+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
12+
</license>
13+
</licenses>
14+
<scm>
15+
<connection>scm:git:https://github.com/firebase/firebase-android-sdk.git</connection>
16+
<url>https://github.com/firebase/firebase-android-sdk</url>
17+
</scm>
18+
<dependencies>
19+
<dependency>
20+
<groupId>org.jetbrains.kotlinx</groupId>
21+
<artifactId>kotlinx-coroutines-play-services</artifactId>
22+
<version>1.6.4</version>
23+
<scope>compile</scope>
24+
<type>jar</type>
25+
</dependency>
26+
<dependency>
27+
<groupId>com.google.firebase</groupId>
28+
<artifactId>firebase-components</artifactId>
29+
<version>18.0.0</version>
30+
<scope>compile</scope>
31+
<type>aar</type>
32+
</dependency>
33+
<dependency>
34+
<groupId>com.google.firebase</groupId>
35+
<artifactId>firebase-annotations</artifactId>
36+
<version>16.2.0</version>
37+
<scope>compile</scope>
38+
<type>jar</type>
39+
</dependency>
40+
<dependency>
41+
<groupId>androidx.annotation</groupId>
42+
<artifactId>annotation</artifactId>
43+
<version>1.5.0</version>
44+
<scope>runtime</scope>
45+
<type>jar</type>
46+
</dependency>
47+
<dependency>
48+
<groupId>androidx.concurrent</groupId>
49+
<artifactId>concurrent-futures</artifactId>
50+
<version>1.1.0</version>
51+
<scope>runtime</scope>
52+
<type>jar</type>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.jetbrains.kotlin</groupId>
56+
<artifactId>kotlin-stdlib</artifactId>
57+
<version>1.8.22</version>
58+
<scope>runtime</scope>
59+
<type>jar</type>
60+
</dependency>
61+
<dependency>
62+
<groupId>com.google.android.gms</groupId>
63+
<artifactId>play-services-basement</artifactId>
64+
<version>18.3.0</version>
65+
<scope>runtime</scope>
66+
<type>aar</type>
67+
</dependency>
68+
<dependency>
69+
<groupId>com.google.android.gms</groupId>
70+
<artifactId>play-services-tasks</artifactId>
71+
<version>18.1.0</version>
72+
<scope>runtime</scope>
73+
<type>aar</type>
74+
</dependency>
75+
</dependencies>
76+
</project>

0 commit comments

Comments
 (0)