1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.clean;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.RandomAccessFile;
25 import java.nio.channels.FileChannel;
26 import java.nio.channels.FileLock;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.Collections;
31
32 import org.apache.maven.api.plugin.MojoException;
33 import org.apache.maven.api.plugin.testing.Basedir;
34 import org.apache.maven.api.plugin.testing.InjectMojo;
35 import org.apache.maven.api.plugin.testing.MojoTest;
36 import org.junit.jupiter.api.Test;
37 import org.junit.jupiter.api.condition.DisabledOnOs;
38 import org.junit.jupiter.api.condition.EnabledOnOs;
39 import org.junit.jupiter.api.condition.OS;
40
41 import static org.apache.maven.api.plugin.testing.MojoExtension.getBasedir;
42 import static org.apache.maven.api.plugin.testing.MojoExtension.setVariableValueToObject;
43 import static org.codehaus.plexus.util.IOUtil.copy;
44 import static org.junit.jupiter.api.Assertions.assertFalse;
45 import static org.junit.jupiter.api.Assertions.assertNotNull;
46 import static org.junit.jupiter.api.Assertions.assertThrows;
47 import static org.junit.jupiter.api.Assertions.assertTrue;
48
49
50
51
52 @MojoTest
53 public class CleanMojoTest {
54
55
56
57
58
59
60 @Test
61 @Basedir("${basedir}/target/test-classes/unit/basic-clean-test")
62 @InjectMojo(goal = "clean")
63 public void testBasicClean(CleanMojo mojo) throws Exception {
64 mojo.execute();
65
66 assertFalse(checkExists(getBasedir() + "/buildDirectory"), "Directory exists");
67 assertFalse(checkExists(getBasedir() + "/buildOutputDirectory"), "Directory exists");
68 assertFalse(checkExists(getBasedir() + "/buildTestDirectory"), "Directory exists");
69 }
70
71
72
73
74
75
76 @Test
77 @Basedir("${basedir}/target/test-classes/unit/nested-clean-test")
78 @InjectMojo(goal = "clean")
79 public void testCleanNestedStructure(CleanMojo mojo) throws Exception {
80 mojo.execute();
81
82 assertFalse(checkExists(getBasedir() + "/target"));
83 assertFalse(checkExists(getBasedir() + "/target/classes"));
84 assertFalse(checkExists(getBasedir() + "/target/test-classes"));
85 }
86
87
88
89
90
91
92
93 @Test
94 @Basedir("${basedir}/target/test-classes/unit/empty-clean-test")
95 @InjectMojo(goal = "clean")
96 public void testCleanEmptyDirectories(CleanMojo mojo) throws Exception {
97 mojo.execute();
98
99 assertTrue(checkExists(getBasedir() + "/testDirectoryStructure"));
100 assertTrue(checkExists(getBasedir() + "/testDirectoryStructure/file.txt"));
101 assertTrue(checkExists(getBasedir() + "/testDirectoryStructure/outputDirectory"));
102 assertTrue(checkExists(getBasedir() + "/testDirectoryStructure/outputDirectory/file.txt"));
103 }
104
105
106
107
108
109
110 @Test
111 @Basedir("${basedir}/target/test-classes/unit/fileset-clean-test")
112 @InjectMojo(goal = "clean")
113 public void testFilesetsClean(CleanMojo mojo) throws Exception {
114 mojo.execute();
115
116
117 assertTrue(checkExists(getBasedir() + "/target"));
118 assertTrue(checkExists(getBasedir() + "/target/classes"));
119 assertFalse(checkExists(getBasedir() + "/target/test-classes"));
120 assertTrue(checkExists(getBasedir() + "/target/subdir"));
121 assertFalse(checkExists(getBasedir() + "/target/classes/file.txt"));
122 assertTrue(checkEmpty(getBasedir() + "/target/classes"));
123 assertFalse(checkEmpty(getBasedir() + "/target/subdir"));
124 assertTrue(checkExists(getBasedir() + "/target/subdir/file.txt"));
125
126
127 assertTrue(checkExists(getBasedir() + "/" + "buildOutputDirectory"));
128 assertFalse(checkExists(getBasedir() + "/" + "buildOutputDirectory/file.txt"));
129 }
130
131
132
133
134
135
136 @Test
137 @Basedir("${basedir}/target/test-classes/unit/invalid-directory-test")
138 @InjectMojo(goal = "clean")
139 public void testCleanInvalidDirectory(CleanMojo mojo) throws Exception {
140 assertThrows(MojoException.class, mojo::execute, "Should fail to delete a file treated as a directory");
141 }
142
143
144
145
146
147
148 @Test
149 @Basedir("${basedir}/target/test-classes/unit/missing-directory-test")
150 @InjectMojo(goal = "clean")
151 public void testMissingDirectory(CleanMojo mojo) throws Exception {
152 mojo.execute();
153
154 assertFalse(checkExists(getBasedir() + "/does-not-exist"));
155 }
156
157
158
159
160
161
162
163
164
165 @Test
166 @EnabledOnOs(OS.WINDOWS)
167 @Basedir("${basedir}/target/test-classes/unit/locked-file-test")
168 @InjectMojo(goal = "clean")
169 public void testCleanLockedFile(CleanMojo mojo) throws Exception {
170 File f = new File(getBasedir(), "buildDirectory/file.txt");
171 try (FileChannel channel = new RandomAccessFile(f, "rw").getChannel();
172 FileLock ignored = channel.lock()) {
173 assertThrows(MojoException.class, () -> mojo.execute());
174 }
175 }
176
177
178
179
180
181
182
183
184
185 @Test
186 @EnabledOnOs(OS.WINDOWS)
187 @Basedir("${basedir}/target/test-classes/unit/locked-file-test")
188 @InjectMojo(goal = "clean")
189 public void testCleanLockedFileWithNoError(CleanMojo mojo) throws Exception {
190 setVariableValueToObject(mojo, "failOnError", Boolean.FALSE);
191 assertNotNull(mojo);
192
193 File f = new File(getBasedir(), "buildDirectory/file.txt");
194 try (FileChannel channel = new RandomAccessFile(f, "rw").getChannel();
195 FileLock ignored = channel.lock()) {
196 mojo.execute();
197 }
198 }
199
200
201
202
203
204 @Test
205 @EnabledOnOs(OS.WINDOWS)
206 public void testFollowLinksWithWindowsJunction() throws Exception {
207 testSymlink((link, target) -> {
208 Process process = new ProcessBuilder()
209 .directory(link.getParent().toFile())
210 .command("cmd", "/c", "mklink", "/j", link.getFileName().toString(), target.toString())
211 .start();
212 process.waitFor();
213 ByteArrayOutputStream baos = new ByteArrayOutputStream();
214 copy(process.getInputStream(), baos);
215 copy(process.getErrorStream(), baos);
216 if (!Files.exists(link)) {
217 throw new IOException("Unable to create junction: " + baos);
218 }
219 });
220 }
221
222
223
224
225
226 @Test
227 @DisabledOnOs(OS.WINDOWS)
228 public void testFollowLinksWithSymLinkOnPosix() throws Exception {
229 testSymlink((link, target) -> {
230 try {
231 Files.createSymbolicLink(link, target);
232 } catch (IOException e) {
233 throw new IOException("Unable to create symbolic link", e);
234 }
235 });
236 }
237
238 @FunctionalInterface
239 interface LinkCreator {
240 void createLink(Path link, Path target) throws Exception;
241 }
242
243 private void testSymlink(LinkCreator linkCreator) throws Exception {
244 Cleaner cleaner = new Cleaner(null, null, false, null, null);
245 Path testDir = Paths.get("target/test-classes/unit/test-dir").toAbsolutePath();
246 Path dirWithLnk = testDir.resolve("dir");
247 Path orgDir = testDir.resolve("org-dir");
248 Path jctDir = dirWithLnk.resolve("jct-dir");
249 Path file = orgDir.resolve("file.txt");
250
251
252 Files.createDirectories(dirWithLnk);
253 Files.createDirectories(orgDir);
254 Files.write(file, Collections.singleton("Hello world"));
255 linkCreator.createLink(jctDir, orgDir);
256
257 cleaner.delete(dirWithLnk, null, false, true, false);
258
259 assertTrue(Files.exists(file));
260 assertFalse(Files.exists(jctDir));
261 assertTrue(Files.exists(orgDir));
262 assertFalse(Files.exists(dirWithLnk));
263
264
265 Files.createDirectories(dirWithLnk);
266 Files.createDirectories(orgDir);
267 Files.write(file, Collections.singleton("Hello world"));
268 linkCreator.createLink(jctDir, orgDir);
269
270 cleaner.delete(dirWithLnk, null, true, true, false);
271
272 assertFalse(Files.exists(file));
273 assertFalse(Files.exists(jctDir));
274 assertTrue(Files.exists(orgDir));
275 assertFalse(Files.exists(dirWithLnk));
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308 private boolean checkExists(String dir) {
309 return new File(new File(dir).getAbsolutePath()).exists();
310 }
311
312
313
314
315
316 private boolean checkEmpty(String dir) {
317 File[] files = new File(dir).listFiles();
318 return files == null || files.length == 0;
319 }
320 }