|
| 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 | +} |
0 commit comments