1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.jarsigner;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.time.Duration;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26 import java.util.concurrent.ExecutorService;
27 import java.util.concurrent.Executors;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.Semaphore;
30 import java.util.concurrent.ThreadFactory;
31 import java.util.concurrent.TimeUnit;
32
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugin.logging.Log;
36 import org.apache.maven.project.MavenProject;
37 import org.apache.maven.shared.jarsigner.JarSigner;
38 import org.apache.maven.shared.jarsigner.JarSignerSignRequest;
39 import org.junit.After;
40 import org.junit.Before;
41 import org.junit.Rule;
42 import org.junit.Test;
43 import org.junit.rules.TemporaryFolder;
44
45 import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_ERROR;
46 import static org.apache.maven.plugins.jarsigner.TestJavaToolResults.RESULT_OK;
47 import static org.hamcrest.CoreMatchers.containsString;
48 import static org.hamcrest.MatcherAssert.assertThat;
49 import static org.junit.Assert.*;
50 import static org.mockito.ArgumentMatchers.any;
51 import static org.mockito.ArgumentMatchers.contains;
52 import static org.mockito.ArgumentMatchers.isA;
53 import static org.mockito.Mockito.*;
54
55 public class JarsignerSignMojoParallelTest {
56 @Rule
57 public TemporaryFolder folder = new TemporaryFolder();
58
59 private MavenProject project = mock(MavenProject.class);
60 private JarSigner jarSigner = mock(JarSigner.class);
61 private File projectDir;
62 private Map<String, String> configuration = new LinkedHashMap<>();
63 private MojoTestCreator<JarsignerSignMojo> mojoTestCreator;
64 private ExecutorService executor;
65 private Log log;
66
67 @Before
68 public void setUp() throws Exception {
69 projectDir = folder.newFolder("dummy-project");
70 configuration.put("processMainArtifact", "false");
71 mojoTestCreator =
72 new MojoTestCreator<JarsignerSignMojo>(JarsignerSignMojo.class, project, projectDir, jarSigner);
73 log = mock(Log.class);
74 mojoTestCreator.setLog(log);
75 executor =
76 Executors.newSingleThreadExecutor(namedThreadFactory(getClass().getSimpleName()));
77 }
78
79 @After
80 public void tearDown() {
81 executor.shutdown();
82 }
83
84 @Test(timeout = 30000)
85 public void test10Files2Parallel() throws Exception {
86 configuration.put("archiveDirectory", createArchives(10).getPath());
87 configuration.put("threadCount", "2");
88
89
90 Semaphore semaphore = new Semaphore(9);
91 when(jarSigner.execute(isA(JarSignerSignRequest.class))).then(invocation -> {
92 semaphore.acquire();
93 return RESULT_OK;
94 });
95 JarsignerSignMojo mojo = mojoTestCreator.configure(configuration);
96
97 Future<Void> future = executor.submit(() -> {
98 mojo.execute();
99 return null;
100 });
101
102
103 verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(10)).execute(any());
104
105 assertFalse(future.isDone());
106
107 semaphore.release();
108 future.get(10, TimeUnit.SECONDS);
109 assertTrue(future.isDone());
110 }
111
112 @Test(timeout = 30000)
113 public void test10Files2Parallel3Hanging() throws Exception {
114 configuration.put("archiveDirectory", createArchives(10).getPath());
115 configuration.put("threadCount", "2");
116
117
118 Semaphore semaphore = new Semaphore(7);
119 when(jarSigner.execute(isA(JarSignerSignRequest.class))).then(invocation -> {
120 semaphore.acquire();
121 return RESULT_OK;
122 });
123 JarsignerSignMojo mojo = mojoTestCreator.configure(configuration);
124
125 Future<Void> future = executor.submit(() -> {
126 mojo.execute();
127 return null;
128 });
129
130
131 verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(9)).execute(any());
132 assertFalse(future.isDone());
133
134 semaphore.release();
135
136
137 verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(10)).execute(any());
138
139 semaphore.release(2);
140 future.get(10, TimeUnit.SECONDS);
141 assertTrue(future.isDone());
142 }
143
144 @Test(timeout = 30000)
145 public void test10Files1Parallel() throws Exception {
146 configuration.put("archiveDirectory", createArchives(10).getPath());
147 configuration.put("threadCount", "1");
148
149
150 Semaphore semaphore = new Semaphore(9);
151 when(jarSigner.execute(isA(JarSignerSignRequest.class))).then(invocation -> {
152 semaphore.acquire();
153 return RESULT_OK;
154 });
155 JarsignerSignMojo mojo = mojoTestCreator.configure(configuration);
156
157 Future<Void> future = executor.submit(() -> {
158 mojo.execute();
159 return null;
160 });
161
162
163 verify(jarSigner, timeout(Duration.ofSeconds(10).toMillis()).times(10)).execute(any());
164 assertFalse(future.isDone());
165
166 semaphore.release();
167 future.get(10, TimeUnit.SECONDS);
168 assertTrue(future.isDone());
169 }
170
171 @Test(timeout = 30000)
172 public void test10Files2ParallelOneFail() throws Exception {
173 configuration.put("archiveDirectory", createArchives(10).getPath());
174 configuration.put("threadCount", "2");
175
176 when(jarSigner.execute(isA(JarSignerSignRequest.class)))
177 .thenReturn(RESULT_OK)
178 .thenReturn(RESULT_OK)
179 .thenReturn(RESULT_ERROR)
180 .thenReturn(RESULT_OK);
181 JarsignerSignMojo mojo = mojoTestCreator.configure(configuration);
182
183 MojoExecutionException mojoException = assertThrows(MojoExecutionException.class, () -> {
184 mojo.execute();
185 });
186
187 assertThat(mojoException.getMessage(), containsString(String.valueOf("Failed executing 'jarsigner ")));
188 }
189
190 @Test
191 public void testInvalidThreadCount() throws Exception {
192 Artifact mainArtifact = TestArtifacts.createJarArtifact(projectDir, "my-project.jar");
193 when(project.getArtifact()).thenReturn(mainArtifact);
194 when(jarSigner.execute(any(JarSignerSignRequest.class))).thenReturn(RESULT_OK);
195 configuration.put("processMainArtifact", "true");
196 configuration.put("threadCount", "0");
197 JarsignerSignMojo mojo = mojoTestCreator.configure(configuration);
198
199 mojo.execute();
200
201 verify(jarSigner, times(1)).execute(any());
202 verify(log).warn(contains("Invalid threadCount value"));
203 verify(log).warn(contains("Was '0'"));
204 }
205
206 private File createArchives(int numberOfArchives) throws IOException {
207 File archiveDirectory = new File(projectDir, "my_archive_dir");
208 archiveDirectory.mkdir();
209 for (int i = 0; i < numberOfArchives; i++) {
210 TestArtifacts.createDummyZipFile(new File(archiveDirectory, "archive" + i + ".jar"));
211 }
212 return archiveDirectory;
213 }
214
215 private static ThreadFactory namedThreadFactory(String threadNamePrefix) {
216 return r -> new Thread(r, threadNamePrefix + "-Thread");
217 }
218 }