View Javadoc
1   package com.atlassian.plugin.loaders;
2   
3   import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
4   import com.atlassian.plugin.loaders.classloading.DirectoryPluginLoaderUtils;
5   import com.atlassian.plugin.loaders.classloading.Scanner;
6   import com.atlassian.plugin.test.PluginTestUtils;
7   import org.apache.commons.io.FileUtils;
8   import org.junit.Before;
9   import org.junit.Test;
10  
11  import javax.annotation.Nonnull;
12  import java.io.File;
13  import java.io.IOException;
14  import java.util.Collection;
15  import java.util.Iterator;
16  import java.util.function.Function;
17  
18  import static com.atlassian.plugin.loaders.classloading.DirectoryPluginLoaderUtils.PADDINGTON_JAR;
19  import static com.atlassian.plugin.loaders.classloading.DirectoryPluginLoaderUtils.POOH_JAR;
20  import static org.apache.commons.lang.SystemUtils.IS_OS_WINDOWS;
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertNotNull;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assume.assumeFalse;
26  
27  public class TestDirectoryScanner {
28  
29      private File pluginsTestDir;
30  
31      @Before
32      public void createFillAndCleanTempPluginDirectory() throws IOException {
33          final DirectoryPluginLoaderUtils.ScannerDirectories directories =
34                  DirectoryPluginLoaderUtils.createFillAndCleanTempPluginDirectory();
35          pluginsTestDir = directories.pluginsTestDir;
36      }
37  
38      @Test
39      public void testNormalOperation() {
40          File pluginsDirectory = pluginsTestDir;
41          Scanner scanner = new DirectoryScanner(pluginsDirectory);
42          scanner.scan();
43          Collection<DeploymentUnit> deployedUnits = scanner.getDeploymentUnits();
44          assertEquals(2, deployedUnits.size());
45  
46          // units should be returned ordered alphabetically
47          Iterator iterator = deployedUnits.iterator();
48          DeploymentUnit unit = (DeploymentUnit) iterator.next();
49          assertEquals(PADDINGTON_JAR, unit.getPath().getName());
50  
51          unit = (DeploymentUnit) iterator.next();
52          assertEquals(POOH_JAR, unit.getPath().getName());
53      }
54  
55      @Test
56      public void testSkipDot() throws Exception {
57          File pluginsDirectory = pluginsTestDir;
58          assertNotNull(File.createTempFile(".asdf", ".jar", pluginsDirectory));
59          Scanner scanner = new DirectoryScanner(pluginsDirectory);
60          scanner.scan();
61          Collection<DeploymentUnit> deployedUnits = scanner.getDeploymentUnits();
62          assertEquals(2, deployedUnits.size());
63  
64          // units should be returned ordered alphabetically
65          Iterator iterator = deployedUnits.iterator();
66          DeploymentUnit unit = (DeploymentUnit) iterator.next();
67          assertEquals(PADDINGTON_JAR, unit.getPath().getName());
68  
69          unit = (DeploymentUnit) iterator.next();
70          assertEquals(POOH_JAR, unit.getPath().getName());
71      }
72  
73      @Test
74      public void testRemove() {
75          File pluginsDirectory = pluginsTestDir;
76          File paddington = new File(pluginsDirectory, PADDINGTON_JAR);
77  
78          assertTrue(paddington.exists());
79  
80          DirectoryScanner scanner = new DirectoryScanner(pluginsDirectory);
81          scanner.scan();
82          assertEquals(2, scanner.getDeploymentUnits().size());
83          DeploymentUnit paddingtonUnit = scanner.locateDeploymentUnit(paddington);
84          scanner.remove(paddingtonUnit);
85  
86          assertFalse(paddington.exists());
87          assertEquals(1, scanner.getDeploymentUnits().size());
88      }
89  
90      @Test
91      public void testRemoveFromReadOnlySource() {
92          // Windows does not support read only directories
93          assumeFalse(IS_OS_WINDOWS);
94  
95          final File pluginsDirectory = pluginsTestDir;
96          final File paddington = new File(pluginsDirectory, PADDINGTON_JAR);
97          try {
98              // Disallow deleting of the file.
99              setWritable(pluginsDirectory, false);
100             // Check that the plugins directory is actually read-only, otherwise skip the test, as it will fail.
101             assumeFalse("Can write to " + pluginsDirectory +
102                     ", even though we made it read-only. Maybe we're running as root?", pluginsDirectory.canWrite());
103             final DirectoryScanner scanner = new DirectoryScanner(pluginsDirectory);
104             scanner.scan();
105             assertEquals(2, scanner.getDeploymentUnits().size());
106             final DeploymentUnit paddingtonUnit = scanner.locateDeploymentUnit(paddington);
107             assertTrue( PADDINGTON_JAR + " should exist before remove() is called", paddington.exists());
108 
109             scanner.remove(paddingtonUnit);
110 
111             assertTrue(PADDINGTON_JAR + " should exist after remove() is called", paddington.exists());
112             assertEquals(1, scanner.getDeploymentUnits().size());
113         } finally {
114             // Reset to writable when we are done
115             setWritable(pluginsDirectory, true);
116         }
117     }
118 
119     @Test
120     public void testRemoveNoErrorWhenNotExist() {
121         File pluginsDirectory = pluginsTestDir;
122         File paddington = new File(pluginsDirectory, PADDINGTON_JAR);
123 
124         assertTrue(paddington.exists());
125 
126         DirectoryScanner scanner = new DirectoryScanner(pluginsDirectory);
127         scanner.scan();
128         assertEquals(2, scanner.getDeploymentUnits().size());
129         DeploymentUnit paddingtonUnit = scanner.locateDeploymentUnit(paddington);
130         assertTrue(paddington.exists());
131         assertTrue(paddington.delete());
132         scanner.remove(paddingtonUnit);
133 
134         assertFalse(paddington.exists());
135         assertEquals(1, scanner.getDeploymentUnits().size());
136     }
137 
138     @Test
139     public void testAddAndRemoveJarFromOutsideScanner() throws Exception {
140         File pluginsDirectory = pluginsTestDir;
141         File paddington = new File(pluginsDirectory, PADDINGTON_JAR);
142         File duplicate = new File(pluginsDirectory, "duplicate-test-plugin.jar");
143 
144         // make sure it's not there already from a bad test
145         if (duplicate.canRead()) {
146             delete(duplicate);
147         }
148 
149         // should be 2 to start with
150         Scanner scanner = new DirectoryScanner(pluginsDirectory);
151         scanner.scan();
152         assertEquals(2, scanner.getDeploymentUnits().size());
153 
154         // copy and scan - should have 3 files
155         FileUtils.copyFile(paddington, duplicate);
156         scanner.scan();
157         assertEquals(3, scanner.getDeploymentUnits().size());
158 
159         // delete and we should have 2!
160         delete(duplicate);
161         scanner.scan();
162         assertEquals(2, scanner.getDeploymentUnits().size());
163     }
164 
165     @Test
166     public void testModifyJar() throws Exception {
167         // Note windows is a piece of shit (can't modify files in the classpath) so
168         // we need to create a temporary directory outside the classpath where we can modify files freely.
169         File pluginsDirectory = pluginsTestDir;
170         File paddington = new File(pluginsDirectory, PADDINGTON_JAR);
171 
172         File testTempDirectory = PluginTestUtils.createTempDirectory(TestDirectoryScanner.class);
173 
174         File newPaddington = new File(testTempDirectory, PADDINGTON_JAR);
175         FileUtils.copyFile(paddington, newPaddington);
176 
177         // set the original mod date - must be a multiple of 1000 on most (all?) file systems
178         long originalModification = System.currentTimeMillis();
179         originalModification = originalModification - (originalModification % 1000) - 3000;
180         setLastModified(newPaddington, originalModification);
181         assertEquals(originalModification, newPaddington.lastModified());
182 
183         // should be 2 to start with
184         DirectoryScanner scanner = new DirectoryScanner(testTempDirectory);
185         scanner.scan();
186         assertEquals(1, scanner.getDeploymentUnits().size());
187 
188         DeploymentUnit newPaddingtonUnit = scanner.locateDeploymentUnit(newPaddington);
189         assertEquals(originalModification, newPaddingtonUnit.lastModified());
190 
191         // modify the JAR file
192         long secondModification = originalModification + 2000;
193         setLastModified(newPaddington, secondModification);
194         scanner.scan();
195 
196         newPaddingtonUnit = scanner.locateDeploymentUnit(newPaddington);
197         assertEquals(secondModification, newPaddingtonUnit.lastModified());
198     }
199 
200     private static void delete(@Nonnull final File file) {
201         confirmModifyFile(file, File::delete);
202     }
203 
204     private static void setLastModified(@Nonnull final File file, final long time) {
205         confirmModifyFile(file, f -> f.setLastModified(time));
206     }
207 
208     private static void setWritable(@Nonnull final File file, final boolean writable) {
209         confirmModifyFile(file, f -> f.setWritable(writable));
210     }
211 
212     private static void confirmModifyFile(@Nonnull final File file, final Function<File, Boolean> operation) {
213         final String message = String.format("Couldn't modify file %s", file);
214         assertTrue(message, operation.apply(file));
215     }
216 }