1 19 20 package org.netbeans.api.project; 21 22 import java.io.IOException ; 23 import java.lang.ref.Reference ; 24 import java.lang.ref.WeakReference ; 25 import java.util.Arrays ; 26 import java.util.Collections ; 27 import java.util.HashSet ; 28 import java.util.Set ; 29 import org.netbeans.junit.NbTestCase; 30 import org.netbeans.modules.projectapi.TimedWeakReference; 31 import org.openide.filesystems.FileObject; 32 import org.openide.util.Lookup; 33 34 37 45 46 50 public class ProjectManagerTest extends NbTestCase { 51 52 static { 53 TimedWeakReference.TIMEOUT = 1000; 55 } 56 57 public ProjectManagerTest(String name) { 58 super(name); 59 } 60 61 private FileObject scratch; 62 private FileObject goodproject; 63 private FileObject goodproject2; 64 private FileObject badproject; 65 private FileObject mysteryproject; 66 private ProjectManager pm; 67 68 protected void setUp() throws Exception { 69 super.setUp(); 70 scratch = TestUtil.makeScratchDir(this); 71 goodproject = scratch.createFolder("good"); 72 goodproject.createFolder("testproject"); 73 goodproject2 = scratch.createFolder("good2"); 74 goodproject2.createFolder("testproject"); 75 badproject = scratch.createFolder("bad"); 76 badproject.createFolder("testproject").createData("broken"); 77 mysteryproject = scratch.createFolder("mystery"); 78 TestUtil.setLookup(new Object [] {TestUtil.testProjectFactory()}); 79 pm = ProjectManager.getDefault(); 80 pm.reset(); 81 TestUtil.BROKEN_PROJECT_LOAD_LOCK = null; 82 ProjectManager.quiet = true; 83 } 84 85 protected void tearDown() throws Exception { 86 scratch = null; 87 goodproject = null; 88 badproject = null; 89 mysteryproject = null; 90 pm = null; 91 super.tearDown(); 92 } 93 94 public void testFindProject() throws Exception { 95 Project p = null; 96 try { 97 p = pm.findProject(goodproject); 98 } catch (IOException e) { 99 fail("Should not fail to load goodproject: " + e); 100 } 101 assertNotNull("Should have recognized goodproject", p); 102 assertEquals("Correct project directory set", goodproject, p.getProjectDirectory()); 103 Project p2 = null; 104 try { 105 p2 = pm.findProject(badproject); 106 fail("Should not have succeeded loading badproject"); 107 } catch (IOException e) { 108 } 110 try { 111 p2 = pm.findProject(mysteryproject); 112 } catch (IOException e) { 113 fail("Should not have failed loading mysteryproject: " + e); 114 } 115 assertNull("Should not have been able to load mysteryproject", p2); 116 assertEquals("Repeated find calls should give same result", p, pm.findProject(goodproject)); 117 assertEquals("ProjectFactory was called only once on goodproject", 1, TestUtil.projectLoadCount(goodproject)); 118 } 119 120 public void testFindProjectGC() throws Exception { 121 Project p = null; 122 try { 123 p = pm.findProject(goodproject); 124 } catch (IOException e) { 125 fail("Should not fail to load goodproject: " + e); 126 } 127 assertNotNull("Should have recognized goodproject", p); 128 assertEquals("ProjectFactory was called once so far on goodproject", 1, TestUtil.projectLoadCount(goodproject)); 129 Reference <?> pref = new WeakReference <Object >(p); 130 p = null; 131 Thread.sleep(TimedWeakReference.TIMEOUT); assertGC("Can collect an unused project with project directory still set", pref); 133 p = pm.findProject(goodproject); 134 assertNotNull("Can load goodproject again", p); 135 assertEquals("Correct project directory set", goodproject, p.getProjectDirectory()); 136 assertEquals("ProjectFactory was called again on goodproject", 2, TestUtil.projectLoadCount(goodproject)); 137 pref = new WeakReference <Object >(p); 138 p = null; 139 Reference <?> dirref = new WeakReference <Object >(goodproject); 140 goodproject = null; 141 assertGC("Collected the project directory", dirref); 142 assertGC("Can collect an unused project with project directory discarded", pref); 143 goodproject = scratch.getFileObject("good"); 144 assertNotNull("goodproject dir still exists", goodproject); 145 p = pm.findProject(goodproject); 146 assertNotNull("Can load goodproject yet again", p); 147 assertEquals("Correct project directory set again", goodproject, p.getProjectDirectory()); 148 assertEquals("ProjectFactory was called only once on new goodproject folder object", 1, TestUtil.projectLoadCount(goodproject)); 149 } 150 151 public void testFindProjectDoesNotCacheLoadErrors() throws Exception { 152 Project p = null; 153 try { 154 p = pm.findProject(badproject); 155 fail("Should not have been able to load badproject"); 156 } catch (IOException e) { 157 } 159 FileObject badprojectSubdir = badproject.getFileObject("testproject"); 160 assertNotNull("Has testproject", badprojectSubdir); 161 FileObject brokenFile = badprojectSubdir.getFileObject("broken"); 162 assertNotNull("Has broken file", brokenFile); 163 brokenFile.delete(); 164 try { 165 p = pm.findProject(badproject); 166 } catch (IOException e) { 167 fail("badproject has been corrected, should not fail to load now: " + e); 168 } 169 assertNotNull("Loaded project", p); 170 assertEquals("Right project dir", badproject, p.getProjectDirectory()); 171 badprojectSubdir.createData("broken"); 172 Project p2 = null; 173 try { 174 p2 = pm.findProject(badproject); 175 } catch (IOException e) { 176 fail("badproject is broken on disk but should still be in cache: " + e); 177 } 178 assertEquals("Cached badproject", p, p2); 179 Reference <?> pref = new WeakReference <Object >(p); 180 p = null; 181 p2 = null; 182 assertGC("Collected badproject cache", pref); 183 try { 184 p = pm.findProject(badproject); 185 fail("Should not have been able to load badproject now that it is rebroken and not in cache"); 186 } catch (IOException e) { 187 } 189 } 190 191 public void testModify() throws Exception { 192 Project p1 = pm.findProject(goodproject); 193 Project p2 = pm.findProject(goodproject2); 194 Set <Project> p1p2 = new HashSet <Project>(Arrays.asList(p1, p2)); 195 assertEquals("start with no modified projects", Collections.emptySet(), pm.getModifiedProjects()); 196 assertTrue("p1 is not yet modified", !pm.isModified(p1)); 197 assertTrue("p2 is not yet modified", !pm.isModified(p2)); 198 TestUtil.modify(p1); 199 assertEquals("just p1 has been modified", Collections.singleton(p1), pm.getModifiedProjects()); 200 assertTrue("p1 is modified", pm.isModified(p1)); 201 assertTrue("p2 is still not modified", !pm.isModified(p2)); 202 TestUtil.modify(p2); 203 assertEquals("now both p1 and p2 have been modified", p1p2, pm.getModifiedProjects()); 204 assertTrue("p1 is modified", pm.isModified(p1)); 205 assertTrue("and p2 is modified too", pm.isModified(p2)); 206 } 207 208 public void testSave() throws Exception { 209 Project p1 = pm.findProject(goodproject); 210 Project p2 = pm.findProject(goodproject2); 211 Set <Project> p1p2 = new HashSet <Project>(Arrays.asList(p1, p2)); 212 assertEquals("start with no modified projects", Collections.emptySet(), pm.getModifiedProjects()); 213 assertEquals("p1 has never been saved", 0, TestUtil.projectSaveCount(p1)); 214 assertEquals("p2 has never been saved", 0, TestUtil.projectSaveCount(p2)); 215 TestUtil.modify(p1); 216 assertEquals("just p1 was modified", Collections.singleton(p1), pm.getModifiedProjects()); 217 TestUtil.modify(p2); 218 assertEquals("both p1 and p2 were modified now", p1p2, pm.getModifiedProjects()); 219 pm.saveProject(p1); 220 assertEquals("p1 was saved so just p2 is modified", Collections.singleton(p2), pm.getModifiedProjects()); 221 assertEquals("p1 was saved once", 1, TestUtil.projectSaveCount(p1)); 222 assertEquals("p2 has not yet been saved", 0, TestUtil.projectSaveCount(p2)); 223 pm.saveProject(p2); 224 assertEquals("now p1 and p2 are both saved", Collections.emptySet(), pm.getModifiedProjects()); 225 assertEquals("p1 was saved once", 1, TestUtil.projectSaveCount(p1)); 226 assertEquals("p2 has now been saved once", 1, TestUtil.projectSaveCount(p2)); 227 pm.saveProject(p2); 228 assertEquals("saving p2 again has no effect", Collections.emptySet(), pm.getModifiedProjects()); 229 assertEquals("p1 still saved just once", 1, TestUtil.projectSaveCount(p1)); 230 assertEquals("redundant call to save did not really save again", 1, TestUtil.projectSaveCount(p2)); 231 TestUtil.modify(p1); 232 TestUtil.modify(p2); 233 assertEquals("both p1 and p2 modified again", p1p2, pm.getModifiedProjects()); 234 pm.saveAllProjects(); 235 assertEquals("saveAllProjects saved both p1 and p2", Collections.EMPTY_SET, pm.getModifiedProjects()); 236 assertEquals("p1 was saved again by saveAllProjects", 2, TestUtil.projectSaveCount(p1)); 237 assertEquals("p2 was saved again by saveAllProjects", 2, TestUtil.projectSaveCount(p2)); 238 pm.saveAllProjects(); 239 assertEquals("saveAllProjects twice has no effect", Collections.EMPTY_SET, pm.getModifiedProjects()); 240 assertEquals("p1 still only saved twice", 2, TestUtil.projectSaveCount(p1)); 241 assertEquals("p2 still only saved twice", 2, TestUtil.projectSaveCount(p2)); 242 } 243 244 public void testSaveError() throws Exception { 245 Project p1 = pm.findProject(goodproject); 246 Project p2 = pm.findProject(goodproject2); 247 TestUtil.modify(p1); 248 TestUtil.modify(p2); 249 Set <Project> p1p2 = new HashSet <Project>(Arrays.asList(p1, p2)); 250 assertEquals("both p1 and p2 are modified", p1p2, pm.getModifiedProjects()); 251 TestUtil.setProjectSaveWillFail(p1, new IOException ("expected")); 252 try { 253 pm.saveProject(p1); 254 fail("Saving p1 should have failed with an IOException"); 255 } catch (IOException e) { 256 } 258 assertTrue("p1 is still modified", pm.isModified(p1)); 259 assertEquals("both p1 and p2 are still modified", p1p2, pm.getModifiedProjects()); 260 pm.saveProject(p1); 261 assertEquals("p1 was saved so just p2 is modified", Collections.singleton(p2), pm.getModifiedProjects()); 262 assertEquals("p1 was saved once", 1, TestUtil.projectSaveCount(p1)); 263 TestUtil.modify(p1); 264 TestUtil.setProjectSaveWillFail(p1, new RuntimeException ("expected")); 265 try { 266 pm.saveProject(p1); 267 fail("Saving p1 should have failed with a RuntimeException"); 268 } catch (RuntimeException e) { 269 } 271 assertTrue("p1 is still modified", pm.isModified(p1)); 272 TestUtil.setProjectSaveWillFail(p1, new Error ("expected")); 273 try { 274 pm.saveProject(p1); 275 fail("Saving p1 should have failed with an Error"); 276 } catch (Error e) { 277 } 279 assertTrue("p1 is still modified", pm.isModified(p1)); 280 assertEquals("both p1 and p2 are still modified", p1p2, pm.getModifiedProjects()); 281 TestUtil.setProjectSaveWillFail(p1, new IOException ("expected")); 282 try { 283 pm.saveAllProjects(); 284 fail("Saving p1 should have failed with an IOException"); 285 } catch (IOException e) { 286 } 288 assertTrue("p1 is still modified", pm.isModified(p1)); 289 assertTrue("p1 is still in the modified set", pm.getModifiedProjects().contains(p1)); 290 assertEquals("p1 was still only saved once", 1, TestUtil.projectSaveCount(p1)); 291 pm.saveAllProjects(); 292 assertEquals("both p1 and p2 are now saved", Collections.EMPTY_SET, pm.getModifiedProjects()); 293 assertEquals("p1 was now saved twice", 2, TestUtil.projectSaveCount(p1)); 294 assertEquals("p2 was saved exactly once (by one or the other saveAllProjects)", 1, TestUtil.projectSaveCount(p2)); 295 } 296 297 public void testClearNonProjectCache() throws Exception { 298 FileObject p1 = scratch.createFolder("p1"); 299 p1.createFolder("testproject"); 300 Project proj1 = pm.findProject(p1); 301 assertNotNull("p1 immediately recognized as a project", proj1); 302 FileObject p2 = scratch.createFolder("p2"); 303 assertNull("p2 not yet recognized as a project", pm.findProject(p2)); 304 FileObject p2a = scratch.createFolder("p2a"); 305 assertNull("p2a not yet recognized as a project", pm.findProject(p2a)); 306 FileObject p3 = scratch.createFolder("p3"); 307 FileObject p3broken = p3.createFolder("testproject").createData("broken"); 308 try { 309 pm.findProject(p3); 310 fail("p3 should throw an error"); 311 } catch (IOException e) { 312 } 314 p2.createFolder("testproject"); 315 p2a.createFolder("testproject"); 316 p3broken.delete(); 317 pm.clearNonProjectCache(); 318 assertNotNull("now p2 is recognized as a project", pm.findProject(p2)); 319 assertNotNull("now p2a is recognized as a project", pm.findProject(p2a)); 320 assertNotNull("now p3 is recognized as a non-broken project", pm.findProject(p3)); 321 assertEquals("p1 still recognized as a project", proj1, pm.findProject(p1)); 322 } 323 324 public void testLoadExceptionWithConcurrentLoad() throws Exception { 325 TestUtil.BROKEN_PROJECT_LOAD_LOCK = new Object (); 326 final Object GOING = new Object (); 327 synchronized (GOING) { 329 new Thread ("initial load") { 330 public void run() { 331 try { 332 synchronized (GOING) { 333 GOING.notify(); 334 } 335 pm.findProject(badproject); 336 assert false : "Should not have loaded project successfully #1"; 337 } catch (IOException e) { 338 } 340 } 341 }.start(); 342 GOING.wait(); 343 } 344 Object previousLoadLock = TestUtil.BROKEN_PROJECT_LOAD_LOCK; 346 TestUtil.BROKEN_PROJECT_LOAD_LOCK = null; synchronized (GOING) { 350 final boolean[] FINISHED_2 = new boolean[1]; 351 new Thread ("parallel load") { 352 public void run() { 353 synchronized (GOING) { 354 GOING.notify(); 355 } 356 try { 357 pm.findProject(badproject); 358 assert false : "Should not have loaded project successfully #2"; 359 } catch (IOException e) { 360 FINISHED_2[0] = true; 362 } 363 synchronized (GOING) { 364 GOING.notify(); 365 } 366 } 367 }.start(); 368 GOING.wait(); 370 assertFalse("not yet finished #2", FINISHED_2[0]); 372 synchronized (previousLoadLock) { 374 previousLoadLock.notify(); 375 } 376 GOING.wait(9999); 378 assertTrue("finished #2 without deadlock", FINISHED_2[0]); 379 } 380 } 381 382 public void testNotifyDeleted() throws Exception { 383 FileObject p1 = scratch.createFolder("p1"); 384 FileObject p1TestProject = p1.createFolder("testproject"); 385 386 Project project1 = pm.findProject(p1); 387 388 assertNotNull("project1 is recognized", project1); 389 p1TestProject.delete(); 390 TestUtil.notifyDeleted(project1); 391 392 assertFalse("project1 is not valid", pm.isValid(project1)); 393 assertNull("project1 is deleted", pm.findProject(p1)); 394 395 FileObject p2 = scratch.createFolder("p2"); 396 FileObject p2TestProject = p2.createFolder("testproject"); 397 398 Project project2 = pm.findProject(p2); 399 400 assertNotNull("project2 is recognized", project2); 401 TestUtil.notifyDeleted(project2); 402 403 assertFalse("project2 is not valid", pm.isValid(project2)); 404 405 Project project2b = pm.findProject(p2); 406 407 assertTrue("project2 is newly recognized", project2b != project2); 408 assertNotNull("project2 is newly recognized", project2b); 409 410 FileObject p3 = scratch.createFolder("p3"); 411 FileObject p3TestProject = p3.createFolder("testproject"); 412 413 Project project3 = pm.findProject(p3); 414 415 assertNotNull("project3 is recognized", project3); 416 TestUtil.modify(project3); 417 assertTrue("project3 is modified", pm.isModified(project3)); 418 TestUtil.notifyDeleted(project3); 419 420 assertFalse("project3 is not valid", pm.isValid(project3)); 421 422 boolean wasException = false; 423 try { 424 pm.isModified(project3); 425 } catch (IllegalArgumentException e) { 426 wasException = true; 428 } 429 430 assertTrue("the project is no longer recognized by the ProjectManager", wasException); 431 432 FileObject p4 = scratch.createFolder("p4"); 433 FileObject p4TestProject = p4.createFolder("testproject"); 434 435 Project project4 = pm.findProject(p4); 436 437 assertNotNull("project4 is recognized", project4); 438 TestUtil.notifyDeleted(project4); 439 440 assertFalse("project4 is not valid", pm.isValid(project3)); 441 442 wasException = false; 443 try { 444 TestUtil.notifyDeleted(project4); 445 } catch (IllegalStateException e) { 446 wasException = true; 448 } 449 450 assertTrue("An IllegalStateException was thrown when calling notifyDeleted twice.", wasException); 451 } 452 453 } 454 | Popular Tags |