View Javadoc

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