• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.internal.dependency
2 
3 import com.google.common.hash.Hashing
4 import com.google.common.io.Files
5 import com.google.common.truth.Truth.assertThat
6 import com.google.common.util.concurrent.Futures
7 import com.google.common.util.concurrent.ListenableFuture
8 import com.google.common.util.concurrent.MoreExecutors
9 import java.io.File
10 import java.io.IOException
11 import java.net.MalformedURLException
12 import java.net.URL
13 import java.nio.charset.StandardCharsets
14 import java.util.concurrent.ExecutorService
15 import org.junit.Assert
16 import org.junit.Before
17 import org.junit.Test
18 import org.junit.runner.RunWith
19 import org.junit.runners.JUnit4
20 
21 @RunWith(JUnit4::class)
22 class MavenDependencyResolverTest {
23   private lateinit var localRepositoryDir: File
24   private lateinit var executorService: ExecutorService
25   private lateinit var mavenDependencyResolver: MavenDependencyResolver
26   private lateinit var mavenArtifactFetcher: TestMavenArtifactFetcher
27 
28   @Before
29   @Throws(Exception::class)
setUpnull30   fun setUp() {
31     executorService = MoreExecutors.newDirectExecutorService()
32     localRepositoryDir = Files.createTempDir()
33     localRepositoryDir.deleteOnExit()
34     mavenArtifactFetcher =
35       TestMavenArtifactFetcher(
36         REPOSITORY_URL,
37         REPOSITORY_USERNAME,
38         REPOSITORY_PASSWORD,
39         PROXY_HOST,
40         PROXY_PORT,
41         localRepositoryDir,
42         executorService
43       )
44     mavenDependencyResolver = TestMavenDependencyResolver()
45   }
46 
47   @Throws(Exception::class)
48   @Test
localArtifactUrl_placesFilesCorrectlyForSingleURLnull49   fun localArtifactUrl_placesFilesCorrectlyForSingleURL() {
50     val dependencyJar = successCases[0]
51     mavenDependencyResolver.getLocalArtifactUrl(dependencyJar)
52     assertThat(mavenArtifactFetcher.numRequests).isEqualTo(4)
53     val artifact = MavenJarArtifact(dependencyJar)
54     checkJarArtifact(artifact)
55   }
56 
57   @Throws(Exception::class)
58   @Test
localArtifactUrl_placesFilesCorrectlyForMultipleURLnull59   fun localArtifactUrl_placesFilesCorrectlyForMultipleURL() {
60     mavenDependencyResolver.getLocalArtifactUrls(*successCases)
61     assertThat(mavenArtifactFetcher.numRequests).isEqualTo(4 * successCases.size)
62     for (dependencyJar in successCases) {
63       val artifact = MavenJarArtifact(dependencyJar)
64       checkJarArtifact(artifact)
65     }
66   }
67 
68   /** Checks the case where the existing artifact directory is valid. */
69   @Throws(Exception::class)
70   @Test
localArtifactUrl_handlesExistingArtifactDirectorynull71   fun localArtifactUrl_handlesExistingArtifactDirectory() {
72     val dependencyJar = DependencyJar("group", "artifact", "1")
73     val mavenJarArtifact = MavenJarArtifact(dependencyJar)
74     val jarFile = File(localRepositoryDir, mavenJarArtifact.jarPath())
75     Files.createParentDirs(jarFile)
76     assertThat(jarFile.parentFile.isDirectory).isTrue()
77     mavenDependencyResolver.getLocalArtifactUrl(dependencyJar)
78     checkJarArtifact(mavenJarArtifact)
79   }
80 
81   /**
82    * Checks the case where there is some existing artifact metadata in the artifact directory, but
83    * not the JAR.
84    */
85   @Throws(Exception::class)
86   @Test
localArtifactUrl_handlesExistingMetadataFilenull87   fun localArtifactUrl_handlesExistingMetadataFile() {
88     val dependencyJar = DependencyJar("group", "artifact", "1")
89     val mavenJarArtifact = MavenJarArtifact(dependencyJar)
90     val pomFile = File(localRepositoryDir, mavenJarArtifact.pomPath())
91     pomFile.parentFile.mkdirs()
92     Files.write(ByteArray(0), pomFile)
93     assertThat(pomFile.exists()).isTrue()
94     mavenDependencyResolver.getLocalArtifactUrl(dependencyJar)
95     checkJarArtifact(mavenJarArtifact)
96   }
97 
98   @Throws(Exception::class)
checkJarArtifactnull99   private fun checkJarArtifact(artifact: MavenJarArtifact) {
100     val jar = File(localRepositoryDir, artifact.jarPath())
101     val pom = File(localRepositoryDir, artifact.pomPath())
102     val jarSha512 = File(localRepositoryDir, artifact.jarSha512Path())
103     val pomSha512 = File(localRepositoryDir, artifact.pomSha512Path())
104     assertThat(jar.exists()).isTrue()
105     assertThat(readFile(jar)).isEqualTo("$artifact jar contents")
106     assertThat(pom.exists()).isTrue()
107     assertThat(readFile(pom)).isEqualTo("$artifact pom contents")
108     assertThat(jarSha512.exists()).isTrue()
109     assertThat(readFile(jarSha512)).isEqualTo(sha512("$artifact jar contents"))
110     assertThat(pom.exists()).isTrue()
111     assertThat(readFile(pomSha512)).isEqualTo(sha512("$artifact pom contents"))
112   }
113 
114   @Throws(Exception::class)
115   @Test
localArtifactUrl_doesNotFetchWhenArtifactsExistnull116   fun localArtifactUrl_doesNotFetchWhenArtifactsExist() {
117     val dependencyJar = DependencyJar("group", "artifact", "1")
118     val mavenJarArtifact = MavenJarArtifact(dependencyJar)
119     val artifactFile = File(localRepositoryDir, mavenJarArtifact.jarPath())
120     artifactFile.parentFile.mkdirs()
121     Files.write(ByteArray(0), artifactFile)
122     assertThat(artifactFile.exists()).isTrue()
123     mavenDependencyResolver.getLocalArtifactUrl(dependencyJar)
124     assertThat(mavenArtifactFetcher.numRequests).isEqualTo(0)
125   }
126 
127   @Throws(Exception::class)
128   @Test
localArtifactUrl_handlesFileNotFoundnull129   fun localArtifactUrl_handlesFileNotFound() {
130     val dependencyJar = DependencyJar("group", "missing-artifact", "1")
131     Assert.assertThrows(AssertionError::class.java) {
132       mavenDependencyResolver.getLocalArtifactUrl(dependencyJar)
133     }
134   }
135 
136   @Throws(Exception::class)
137   @Test
localArtifactUrl_handlesInvalidSha512null138   fun localArtifactUrl_handlesInvalidSha512() {
139     val dependencyJar = DependencyJar("group", "artifact-invalid-sha512", "1")
140     addTestArtifactInvalidSha512(dependencyJar)
141     Assert.assertThrows(AssertionError::class.java) {
142       mavenDependencyResolver.getLocalArtifactUrl(dependencyJar)
143     }
144   }
145 
146   internal inner class TestMavenDependencyResolver : MavenDependencyResolver() {
createMavenFetchernull147     override fun createMavenFetcher(
148       repositoryUrl: String?,
149       repositoryUserName: String?,
150       repositoryPassword: String?,
151       proxyHost: String?,
152       proxyPort: Int,
153       localRepositoryDir: File,
154       executorService: ExecutorService
155     ): MavenArtifactFetcher {
156       return mavenArtifactFetcher
157     }
158 
createExecutorServicenull159     override fun createExecutorService(): ExecutorService {
160       return executorService
161     }
162 
createLockFilenull163     override fun createLockFile(): File {
164       return try {
165         File.createTempFile("MavenDependencyResolverTest", null)
166       } catch (e: IOException) {
167         throw AssertionError(e)
168       }
169     }
170   }
171 
172   internal class TestMavenArtifactFetcher(
173     repositoryUrl: String?,
174     repositoryUserName: String?,
175     repositoryPassword: String?,
176     proxyHost: String?,
177     proxyPort: Int,
178     localRepositoryDir: File,
179     private val executorService: ExecutorService
180   ) :
181     MavenArtifactFetcher(
182       repositoryUrl,
183       repositoryUserName,
184       repositoryPassword,
185       proxyHost,
186       proxyPort,
187       localRepositoryDir,
188       executorService
189     ) {
190     var numRequests = 0
191       private set
192 
createFetchToFileTasknull193     override fun createFetchToFileTask(remoteUrl: URL, tempFile: File): ListenableFuture<Void> {
194       return Futures.submitAsync(
195         object : FetchToFileTask(remoteUrl, tempFile, null, null, null, 0) {
196           @Throws(Exception::class)
197           override fun call(): ListenableFuture<Void> {
198             numRequests += 1
199             return super.call()
200           }
201         },
202         executorService
203       )
204     }
205   }
206 
207   companion object {
208     private var REPOSITORY_DIR: File
209     private var REPOSITORY_URL: String
210     private const val REPOSITORY_USERNAME = "username"
211     private const val REPOSITORY_PASSWORD = "password"
212     private const val PROXY_HOST = "123.4.5.678"
213     private const val PROXY_PORT = 9000
214     private val SHA512 = Hashing.sha512()
215     private val successCases =
216       arrayOf(
217         DependencyJar("group", "artifact", "1"),
218         DependencyJar("org.group2", "artifact2-name", "2.4.5"),
219         DependencyJar("org.robolectric", "android-all", "10-robolectric-5803371")
220       )
221 
222     init {
223       try {
224         REPOSITORY_DIR = Files.createTempDir()
225         REPOSITORY_DIR.deleteOnExit()
226         REPOSITORY_URL = REPOSITORY_DIR.toURI().toURL().toString()
227         for (dependencyJar in successCases) {
228           addTestArtifact(dependencyJar)
229         }
230       } catch (e: Exception) {
231         throw AssertionError(e)
232       }
233     }
234 
235     @Throws(IOException::class)
addTestArtifactnull236     fun addTestArtifact(dependencyJar: DependencyJar?) {
237       val mavenJarArtifact = MavenJarArtifact(dependencyJar)
238       try {
239         Files.createParentDirs(File(REPOSITORY_DIR, mavenJarArtifact.jarPath()))
240         val jarContents = "$mavenJarArtifact jar contents"
241         Files.write(
242           jarContents.toByteArray(StandardCharsets.UTF_8),
243           File(REPOSITORY_DIR, mavenJarArtifact.jarPath())
244         )
245         Files.write(
246           sha512(jarContents).toByteArray(),
247           File(REPOSITORY_DIR, mavenJarArtifact.jarSha512Path())
248         )
249         val pomContents = "$mavenJarArtifact pom contents"
250         Files.write(
251           pomContents.toByteArray(StandardCharsets.UTF_8),
252           File(REPOSITORY_DIR, mavenJarArtifact.pomPath())
253         )
254         Files.write(
255           sha512(pomContents).toByteArray(),
256           File(REPOSITORY_DIR, mavenJarArtifact.pomSha512Path())
257         )
258       } catch (e: MalformedURLException) {
259         throw AssertionError(e)
260       }
261     }
262 
263     @Throws(IOException::class)
addTestArtifactInvalidSha512null264     fun addTestArtifactInvalidSha512(dependencyJar: DependencyJar?) {
265       val mavenJarArtifact = MavenJarArtifact(dependencyJar)
266       try {
267         Files.createParentDirs(File(REPOSITORY_DIR, mavenJarArtifact.jarPath()))
268         val jarContents = "$mavenJarArtifact jar contents"
269         Files.write(jarContents.toByteArray(), File(REPOSITORY_DIR, mavenJarArtifact.jarPath()))
270         Files.write(
271           sha512("No the same content").toByteArray(),
272           File(REPOSITORY_DIR, mavenJarArtifact.jarSha512Path())
273         )
274         val pomContents = "$mavenJarArtifact pom contents"
275         Files.write(pomContents.toByteArray(), File(REPOSITORY_DIR, mavenJarArtifact.pomPath()))
276         Files.write(
277           sha512("Really not the same content").toByteArray(),
278           File(REPOSITORY_DIR, mavenJarArtifact.pomSha512Path())
279         )
280       } catch (e: MalformedURLException) {
281         throw AssertionError(e)
282       }
283     }
284 
sha512null285     fun sha512(contents: String): String {
286       return SHA512.hashString(contents, StandardCharsets.UTF_8).toString()
287     }
288 
289     @Throws(IOException::class)
readFilenull290     fun readFile(file: File): String {
291       return String(Files.asByteSource(file).read(), StandardCharsets.UTF_8)
292     }
293   }
294 }
295