View Javadoc
1   /**
2    * Copyright (c) 2012-2014, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.aether;
31  
32  import com.jcabi.log.Logger;
33  import com.jcabi.log.VerboseRunnable;
34  import com.jcabi.log.VerboseThreads;
35  import java.io.File;
36  import java.util.Arrays;
37  import java.util.Collection;
38  import java.util.LinkedList;
39  import java.util.List;
40  import java.util.concurrent.Callable;
41  import java.util.concurrent.CountDownLatch;
42  import java.util.concurrent.ExecutorService;
43  import java.util.concurrent.Executors;
44  import java.util.concurrent.TimeUnit;
45  import org.apache.maven.project.MavenProject;
46  import org.hamcrest.CustomMatcher;
47  import org.hamcrest.Matcher;
48  import org.hamcrest.MatcherAssert;
49  import org.hamcrest.Matchers;
50  import org.junit.Assert;
51  import org.junit.Rule;
52  import org.junit.Test;
53  import org.junit.rules.TemporaryFolder;
54  import org.mockito.Mockito;
55  import org.sonatype.aether.artifact.Artifact;
56  import org.sonatype.aether.repository.Authentication;
57  import org.sonatype.aether.repository.RemoteRepository;
58  import org.sonatype.aether.resolution.DependencyResolutionException;
59  import org.sonatype.aether.util.artifact.DefaultArtifact;
60  import org.sonatype.aether.util.artifact.JavaScopes;
61  
62  /**
63   * Test case for {@link Aether}.
64   * @author Yegor Bugayenko (yegor@tpc2.com)
65   * @version $Id$
66   * @checkstyle ClassDataAbstractionCoupling (500 lines)
67   */
68  @SuppressWarnings({ "PMD.DoNotUseThreads", "PMD.TooManyMethods" })
69  public final class AetherTest {
70  
71      /**
72       * AWS Key.
73       */
74      private static final String AWS_KEY = System.getProperty("aws.key");
75  
76      /**
77       * AWS Secret key.
78       */
79      private static final String AWS_SECRET = System.getProperty("aws.secret");
80  
81      /**
82       * Temp dir.
83       * @checkstyle VisibilityModifier (3 lines)
84       */
85      @Rule
86      public final transient TemporaryFolder temp = new TemporaryFolder();
87  
88      /**
89       * Aether can find and load artifacts.
90       * @throws Exception If there is some problem inside
91       */
92      @Test
93      public void findsAndLoadsArtifacts() throws Exception {
94          final File local = this.temp.newFolder();
95          final Aether aether = new Aether(this.project(), local);
96          final Collection<DefaultArtifact> artifacts =
97              new LinkedList<DefaultArtifact>(
98                  Arrays.asList(
99                      new DefaultArtifact("com.jcabi:jcabi-log:pom:1.0-SNAPSHOT"),
100                     new DefaultArtifact("log4j:log4j:jar:1.2.16")
101                 )
102             );
103         if (AetherTest.AWS_KEY != null) {
104             artifacts.add(
105                 new DefaultArtifact(
106                     "com.jcabi.aether-test:parent:pom:1.0"
107                 )
108             );
109         }
110         final Matcher<?> matcher = new CustomMatcher<String>("file exists") {
111             @Override
112             public boolean matches(final Object file) {
113                 return File.class.cast(file).exists();
114             }
115         };
116         for (final Artifact artifact : artifacts) {
117             MatcherAssert.assertThat(
118                 aether.resolve(artifact, JavaScopes.RUNTIME),
119                 Matchers.<Artifact>everyItem(
120                     Matchers.<Artifact>hasProperty("file", matcher)
121                 )
122             );
123         }
124     }
125 
126     /**
127      * Aether can resolve in parallel threads.
128      * @throws Exception If there is some problem inside
129      */
130     @Test
131     public void resolvesArtifactsInParallelThreads() throws Exception {
132         final File local = this.temp.newFolder();
133         final Aether aether = new Aether(this.project(), local);
134         final int threads = Runtime.getRuntime().availableProcessors() * 5;
135         final Artifact artifact = new DefaultArtifact(
136             "com.jcabi:jcabi-assembly:pom:0.1.10"
137         );
138         final CountDownLatch start = new CountDownLatch(1);
139         final CountDownLatch latch = new CountDownLatch(threads);
140         final Runnable task = new VerboseRunnable(
141             new Callable<Void>() {
142                 @Override
143                 public Void call() throws Exception {
144                     start.await();
145                     MatcherAssert.assertThat(
146                         aether.resolve(artifact, JavaScopes.RUNTIME),
147                         Matchers.not(Matchers.<Artifact>empty())
148                     );
149                     latch.countDown();
150                     return null;
151                 }
152             },
153             true
154         );
155         final ExecutorService svc =
156             Executors.newFixedThreadPool(threads, new VerboseThreads());
157         for (int thread = 0; thread < threads; ++thread) {
158             svc.submit(task);
159         }
160         start.countDown();
161         MatcherAssert.assertThat(
162             latch.await(2, TimeUnit.MINUTES),
163             Matchers.is(true)
164         );
165         svc.shutdown();
166     }
167 
168     /**
169      * Aether can reject NULL Maven project.
170      * @throws Exception If there is some problem inside
171      */
172     @Test(expected = javax.validation.ConstraintViolationException.class)
173     public void rejectsNullMavenProject() throws Exception {
174         final MavenProject project = null;
175         new Aether(project, this.temp.newFolder());
176     }
177 
178     /**
179      * Aether can reject NULL repository path.
180      * @throws Exception If there is some problem inside
181      */
182     @Test(expected = javax.validation.ConstraintViolationException.class)
183     public void rejectsNullRepoPath() throws Exception {
184         new Aether(this.project(), null);
185     }
186 
187     /**
188      * Aether can reject NULL artifact.
189      * @throws Exception If there is some problem inside
190      */
191     @Test(expected = javax.validation.ConstraintViolationException.class)
192     public void rejectsNullArtifact() throws Exception {
193         new Aether(this.project(), this.temp.newFolder())
194             .resolve(null, JavaScopes.RUNTIME);
195     }
196 
197     /**
198      * Aether can reject NULL scope.
199      * @throws Exception If there is some problem inside
200      */
201     @Test(expected = javax.validation.ConstraintViolationException.class)
202     public void rejectsNullScope() throws Exception {
203         new Aether(this.project(), this.temp.newFolder())
204             .resolve(new DefaultArtifact("junit:junit:4.10"), null);
205     }
206 
207     /**
208      * Aether can throw on non-found artifact.
209      * @throws Exception If there is some problem inside
210      */
211     @Test(expected = DependencyResolutionException.class)
212     public void throwsWhenArtifactNotFound() throws Exception {
213         new Aether(this.project(), this.temp.newFolder()).resolve(
214             new DefaultArtifact("com.jcabi:jcabi-log:jar:0.0.0"),
215             JavaScopes.COMPILE
216         );
217     }
218 
219     /**
220      * Aether can recover after failure.
221      * @throws Exception If there is some problem inside
222      */
223     @Test
224     public void recoversAfterFailure() throws Exception {
225         final Aether aether = new Aether(
226             this.project(),
227             this.temp.newFolder()
228         );
229         try {
230             aether.resolve(
231                 new DefaultArtifact("com.jcabi:jcabi-x:jar:0.0.0"),
232                 JavaScopes.TEST
233             );
234             Assert.fail("expection expected here");
235         } catch (final DependencyResolutionException ex) {
236             MatcherAssert.assertThat(
237                 Logger.format("%[exception]s", ex),
238                 Matchers.allOf(
239                     Matchers.containsString("oss.sonatype.org"),
240                     Matchers.containsString("repo1.maven.org"),
241                     Matchers.containsString("without authentication")
242                 )
243             );
244             if (AetherTest.AWS_KEY != null) {
245                 MatcherAssert.assertThat(
246                     Logger.format("%[exception]s ", ex),
247                     Matchers.allOf(
248                         Matchers.containsString("aether-test.jcabi.com"),
249                         Matchers.containsString(AetherTest.AWS_KEY),
250                         Matchers.not(
251                             Matchers.containsString(AetherTest.AWS_SECRET)
252                         )
253                     )
254                 );
255             }
256         }
257         MatcherAssert.assertThat(
258             aether.resolve(
259                 new DefaultArtifact("com.jcabi:jcabi-log:jar:0.1.8"),
260                 JavaScopes.RUNTIME
261             ),
262             Matchers.not(Matchers.<Artifact>empty())
263         );
264     }
265 
266     /**
267      * Make mock maven project.
268      * @return The project
269      * @throws Exception If there is some problem inside
270      */
271     private MavenProject project() throws Exception {
272         final MavenProject project = Mockito.mock(MavenProject.class);
273         final String type = "default";
274         final List<RemoteRepository> repos = new LinkedList<RemoteRepository>(
275             Arrays.asList(
276                 new RemoteRepository(
277                     "sonatype",
278                     type,
279                     "https://oss.sonatype.org/content/groups/public"
280                 ),
281                 new RemoteRepository(
282                     "maven-central",
283                     type,
284                     "http://repo1.maven.org/maven2/"
285                 ),
286                 new RemoteRepository(
287                     "invalid-http-repository",
288                     type,
289                     "http://repo1.maven.org/invalid-maven-repo/"
290                 ),
291                 new RemoteRepository(
292                     "invalid-s3-repository",
293                     type,
294                     "s3://invalid-s3-repository/"
295                 )
296             )
297         );
298         if (AetherTest.AWS_KEY != null) {
299             final RemoteRepository aws = new RemoteRepository(
300                 "aether-test",
301                 type,
302                 "s3://aether-test.jcabi.com/release"
303             );
304             aws.setAuthentication(
305                 new Authentication(
306                     AetherTest.AWS_KEY,
307                     AetherTest.AWS_SECRET
308                 )
309             );
310             repos.add(aws);
311         }
312         Mockito.doReturn(repos).when(project).getRemoteProjectRepositories();
313         return project;
314     }
315 
316 }