View Javadoc
1   package com.atlassian.plugin.loaders;
2   
3   import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
4   import com.atlassian.plugin.test.PluginTestUtils;
5   import com.google.common.base.Function;
6   import org.apache.commons.io.FileUtils;
7   import org.hamcrest.Matcher;
8   import org.junit.After;
9   import org.junit.Before;
10  import org.junit.Test;
11  
12  import java.io.File;
13  import java.io.IOException;
14  import java.util.Arrays;
15  import java.util.Collection;
16  import java.util.List;
17  
18  import static com.atlassian.plugin.loaders.classloading.TestDeploymentUnit.deploymentUnitWithPath;
19  import static com.google.common.collect.Lists.transform;
20  import static org.apache.commons.io.FileUtils.deleteQuietly;
21  import static org.hamcrest.MatcherAssert.assertThat;
22  import static org.hamcrest.Matchers.containsInAnyOrder;
23  import static org.hamcrest.Matchers.empty;
24  import static org.hamcrest.Matchers.equalTo;
25  import static org.hamcrest.Matchers.is;
26  
27  public class TestRosterFileScanner {
28      private File temporaryDirectory;
29      private File rosterFile;
30  
31      private RosterFileScanner rosterFileScanner;
32  
33      @Before
34      public void setUp() throws Exception {
35          temporaryDirectory = PluginTestUtils.createTempDirectory(RosterFileScanner.class);
36          rosterFile = new File(temporaryDirectory, "rosterFile.list");
37          rosterFileScanner = new RosterFileScanner(rosterFile);
38      }
39  
40      @After
41      public void tearDown() throws Exception {
42          deleteQuietly(temporaryDirectory);
43      }
44  
45      @Test
46      public void scanOfMissingFileIsEmpty() {
47          assertThat(rosterFileScanner.scan(), empty());
48      }
49  
50      @Test
51      public void scanAndGetDeploymentUnitsWithAbsolutePaths() throws Exception {
52          final List<File> expectedFiles = writeRosterFile(rosterFile, "/absoluteSimple", "/absolute/compound");
53  
54          // First scan should yield expected deployment units
55          assertThat(rosterFileScanner.scan(), containsDeploymentUnitsFor(expectedFiles));
56          // A get should also yield expected deployment units
57          assertThat(rosterFileScanner.getDeploymentUnits(), containsDeploymentUnitsFor(expectedFiles));
58      }
59  
60      @Test
61      public void scanAndGetDeploymentUnitsWithRelativePaths() throws Exception {
62          final List<File> expectedFiles = writeRosterFile(rosterFile, "relativeSimple", "relative/simple");
63  
64          // First scan should yield expected deployment units
65          assertThat(rosterFileScanner.scan(), containsDeploymentUnitsFor(expectedFiles));
66          // A get should also yield expected deployment units
67          assertThat(rosterFileScanner.getDeploymentUnits(), containsDeploymentUnitsFor(expectedFiles));
68      }
69  
70      @Test
71      public void getDeploymentUnitsIsEmptyBeforeScan() {
72          assertThat(rosterFileScanner.getDeploymentUnits(), empty());
73      }
74  
75      @Test
76      public void scanAfterResetReturnsDeploymentUnits() throws Exception {
77          final List<File> expectedFiles = writeRosterFile(rosterFile, "/one", "/two");
78  
79          // First scan should yield expected deployment units
80          assertThat(rosterFileScanner.scan(), containsDeploymentUnitsFor(expectedFiles));
81          // A get should also yield expected deployment units
82          assertThat(rosterFileScanner.getDeploymentUnits(), containsDeploymentUnitsFor(expectedFiles));
83          // Subsequent scan should yield no new deployment units
84          assertThat(rosterFileScanner.scan(), empty());
85  
86          rosterFileScanner.reset();
87  
88          // After reset, a get should see nothing
89          assertThat(rosterFileScanner.getDeploymentUnits(), empty());
90          // A new scan should yield the expected deployment units
91          assertThat(rosterFileScanner.scan(), containsDeploymentUnitsFor(expectedFiles));
92          // At which point get should see them also
93          assertThat(rosterFileScanner.getDeploymentUnits(), containsDeploymentUnitsFor(expectedFiles));
94      }
95  
96      @Test
97      public void scanAfterFileUpdateYieldsNewUnits() throws Exception {
98          final List<File> expectedBefore = writeRosterFile(rosterFile, "/one", "/two", "/three");
99          // We need the file modified time to change when we update it, so just backdate the first copy
100         backdateFile(rosterFile);
101 
102         assertThat(rosterFileScanner.scan(), containsDeploymentUnitsFor(expectedBefore));
103         assertThat(rosterFileScanner.getDeploymentUnits(), containsDeploymentUnitsFor(expectedBefore));
104 
105         final List<File> expectedGetAfter = writeRosterFile(rosterFile, "/three", "/four", "/five");
106         // This is a tiny bit brittle, but doing better is quite a pain - we know only 1 element is common with before
107         final List<File> expectedScanAfter = expectedGetAfter.subList(1, expectedGetAfter.size());
108 
109         assertThat(rosterFileScanner.scan(), containsDeploymentUnitsFor(expectedScanAfter));
110         assertThat(rosterFileScanner.getDeploymentUnits(), containsDeploymentUnitsFor(expectedGetAfter));
111     }
112 
113     @Test
114     public void removeDoesNotFail() {
115         final DeploymentUnit deploymentUnit = new DeploymentUnit(new File("removed"));
116         rosterFileScanner.remove(deploymentUnit);
117     }
118 
119     @Test
120     public void isKnownRosterFileFormatTrueForList() {
121         assertThat(RosterFileScanner.isKnownRosterFileFormat(new File("some.list")), is(true));
122     }
123 
124     @Test
125     public void isKnownRosterFileFormatFalseForUnsuffixed() {
126         assertThat(RosterFileScanner.isKnownRosterFileFormat(new File("unsuffixed")), is(false));
127     }
128 
129     public static List<File> writeRosterFile(final File rosterFile, final String... paths)
130             throws IOException {
131         final List<String> listOfPaths = Arrays.asList(paths);
132         FileUtils.writeLines(rosterFile, listOfPaths);
133         return transform(listOfPaths, new Function<String, File>() {
134             @Override
135             public File apply(final String path) {
136                 // Infer whether the path is absolute or not. A quick check is good enough for tests where we control the input
137                 // data, and has the added advantage of keeping us independent of the implementation of this feature.
138                 final boolean absolute = File.separatorChar == path.charAt(0);
139                 return absolute ? new File(path) : new File(rosterFile.getParentFile(), path);
140             }
141         });
142     }
143 
144     public static void backdateFile(final File file) throws Exception {
145         if (!file.setLastModified(file.lastModified() - 2000)) {
146             throw new Exception("Unable to backdate file '" + file + "'");
147         }
148     }
149 
150     private static Matcher<Iterable<? extends DeploymentUnit>> containsDeploymentUnitsFor(final List<File> files) {
151         final List<Matcher<DeploymentUnit>> matchers = transform(files, new Function<File, Matcher<DeploymentUnit>>() {
152             @Override
153             public Matcher<DeploymentUnit> apply(final File file) {
154                 return deploymentUnitWithPath(equalTo(file));
155             }
156         });
157 
158         // I don't seem able to get the right overload of containsInAnyOrder without the unchecked cast
159         //noinspection unchecked
160         return containsInAnyOrder((Collection) matchers);
161     }
162 }