Last week we fixed a bug in 3.0.1 where Dali was not closing InputStreams (bug 244268 <https://bugs.eclipse.org/244268>). After fixing this bug I was able to remove our unit test workarounds for deleting projects (using ProjectUtility and creating new projects with unique names). We no longer have any difficulty with deleting projects in our unit tests. I mention this in case other teams have the same problem, a review of InputStream usage might be in order.

thanks,
Karen

Jason A Sholl wrote:


Take a look at org.eclipse.wst.common.tests.ProjectUtility in the org.eclipse.wst.common.tests plugin. There is a method in there for deleting projects as well.

Thank you,

Jason A. Sholl
[EMAIL PROTECTED]
919-543-0011 (t/l 441-0011)




*"Mitov, Kiril" <[EMAIL PROTECTED]>*
Sent by: [EMAIL PROTECTED]

02/01/2008 07:47 AM
Please respond to
"General discussion of project-wide or architectural issues." <[email protected]>


        
To
"General discussion of project-wide or architectural issues." <[email protected]>
cc
        
Subject
        RE: [wtp-dev] JUnit tip: How to delete projects



        





When it comes to deleting files I have once implemented this method
*private* *void* deleteFileAndUpdate(IFile file) *throws* Exception { ChangeListenerWithSemaphore listener = *new* ChangeListenerWithSemaphore(1); ResourcesPlugin./getWorkspace/().addResourceChangeListener(listener, IResourceChangeEvent./POST_CHANGE/);
            *int* retries = 3;
            *while* (retries > 0) {
                  *try* {
                        /deleteFile/(file);
                        *if* (listener.waitForEvents()) {
                              retries = 0;
                              *break*;
                        }
                  } *catch* (CoreException e) {
                      ... more core here... see in the description.
                  } *finally* {
                        retries--;
                  }
            }
            /assertTrue/(retries == -1);
ResourcesPlugin./getWorkspace/().removeResourceChangeListener(listener);
      }
The basic idea here is that you have not deleted a file/folder/project until you receive a ResourceChangeEvent for the deletion. Since the event might be in the *same thread *or in *another thread *it is important to stop the current thread until an event occurs. This is what I am doing here. This has also worked for folders and projects. The *listener.waitForEvents() *is blocking the current thread until a notification for the deletion is received. In general the thread is blocked until the *specified number of events *(the number in the constructor of ChangeListenerWithSemaphore) is reached. But this can easily be changed to an another logic. Here the "retires" are the number of failiers that I am willing to accept. In the catch(CoreException e) there is a special logic. If the message of the exception is "The requested operation cannot be performed on a file with a user-mapped section open" the code of the catch block is: /* * An exception was occurring - "The requested operation cannot * be performed on a file with a user-mapped section open".
                         * Running the finalization as suggested at
* http://webteam.archive.org/jira/browse/HER-661?decorator=printable
                         */
                        System./runFinalization/();
                        System./gc/();

But I was unable to investigate the error more deeply.

The deleteFile method is:
*protected* *static* *boolean* deleteFile(*final* IFile file) *throws* Exception { ResourcesPlugin./getWorkspace/().run(*new* IWorkspaceRunnable() { *public* *void* run(IProgressMonitor monitor) *throws* CoreException {
                        file.delete(*false*, monitor);
                  }
            }, monitor);
            *return* *true*;
}

The code of ChangeListenerWithSemaphore is
/**
* This change listener will release a semaphore after the resource changed * method is called. For every resourceChanged call one release will be called.
 *
 * [EMAIL PROTECTED] Kiril Mitov [EMAIL PROTECTED]
 *
 */
*public* *final* *class* ChangeListenerWithSemaphore *implements* IResourceChangeListener {
      *private* *final* Semaphore s;
      *private* *final* List<Object> deltas;
      *private* *final* *int* expectedEvents;
      *private* *final* List<IResourceChangeEvent> receivedEvents;
*public* ChangeListenerWithSemaphore(*int* expectedEvents) *throws* InterruptedException {
            *this*.expectedEvents = expectedEvents;
            *this*.s = *new* Semaphore(1);
            *this*.s.acquire();
*this*.deltas = Collections./synchronizedList/(*new* LinkedList<Object>()); *this*.receivedEvents = Collections./synchronizedList/(*new* LinkedList<IResourceChangeEvent>());
      }
*public* *synchronized* *void* resourceChanged(IResourceChangeEvent event) {
            receivedEvents.add(event);
            *if* (receivedEvents.size() > expectedEvents)
*throw* *new* IllegalStateException("The expected events were already reached");
            *try* {
                  deltas.add(event.getDelta());
            } *catch* (Exception e) {
Activator./getDefault/().getLog().log(*new* Status(IStatus./ERROR/, Activator./PLUGIN_ID/, e.getMessage(), e));
                  *return*;
            } *finally* {
                  *if* (expectedEvents == receivedEvents.size())
                        s.release();
            }
      }
*public* *boolean* waitForEvents() *throws* InterruptedException {
            *return* s.tryAcquire(5, TimeUnit./SECONDS/);
      }
*public* *synchronized* List<Object> getDeltas() {
            *return* deltas;
      }
*public* *synchronized* *int* getEvents() {
            *return* receivedEvents.size();
      }
*public* List<IResourceChangeEvent> getReceivedEvents() {
            *return* receivedEvents;
      }
}
This is how I am creating, deleting and updating files.
Best Regards,
Kiril

------------------------------------------------------------------------
*From:* [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] *On Behalf Of *David M Williams*
Sent:* Friday, 1. February 2008 10:16*
To:* [EMAIL PROTECTED]
Subject:* [wtp-dev] JUnit tip: How to delete projects


Some of our JUnits suites require that projects or other resources be deleted during the test, for various reasons, and I think some of the "random errors" we see are because it's hard to delete a project, or file, in a multi-threaded Eclipse. If there is a file from the project open in another thread, for example, perhaps in a thread that's running validation, hence reading files, the delete will fail ("randomly") and then that might cause a JUnit test to fail, directly or indirectly (by having an unexpected state).

I had to solve this, just this evening, and took me a while, reading platform test examples, and googling around, to find a solution that I think is fairly good ... for JUnit tests, at least.

I've pasted the code below ... just in case it helps anyone. Hopefully the constants are obvious, but if anyone wants to see the whole class, it is
org.eclipse.jst.jsp.core.tests.taglibindex.TestIndex

And ... as always the case in open development ... if anyone has other tips/tricks, or better ways, feel free to let us know.

Thanks,




       /**
* It's not easy to delete projects. If any of it's files are open by another thread, * the operation will fail. So, this method will make several attempts before giving up.
        * [EMAIL PROTECTED] project
        * [EMAIL PROTECTED] CoreException
        * [EMAIL PROTECTED] InterruptedException
        */
*private* *void* deleteProject(IProject project) *throws* CoreException, InterruptedException {
               *int* nTrys = 0;
*while* (project != *null* && project.exists() && nTrys < MAX_RETRYS) {
                       *try* {
                               nTrys++;
                               project.delete(*true*, *true*, *null*);
                       }
                       *catch* (ResourceException e) {
                               *if* (DEBUG) {
                                       System./out/.println();
System./out/.println("Could not delete project on attempt number: "+ nTrys);
                                       IStatus eStatus = e.getStatus();
// should always be MultiStatus, but we'll check *if* (eStatus *instanceof* MultiStatus) { MultiStatus mStatus = (MultiStatus) eStatus; IStatus[] iStatus = mStatus.getChildren(); *for* (*int* j = 0; j < iStatus.length; j++) { System./out/.println("Status: " + j + " " + iStatus[j]);
                                               }
                                       }
                                       *else* {
System./out/.println("Status: " + eStatus);
                                       }
                               }
                               /*
* If we could not delete the first time, wait a bit and * re-try. If we could not delete, it is likely because * another thread has a file open, or similar (such as the
                                * validation thread).
                                */
                               Thread./sleep/(PAUSE_TIME);
                       }
               }
*if* (project != *null* && project.exists()) { /fail/("Error in test infrastructure. Could not delete project " + project + " after " + MAX_RETRYS + "attempts.");
               }
       }_______________________________________________
wtp-dev mailing list
[email protected]
https://dev.eclipse.org/mailman/listinfo/wtp-dev

------------------------------------------------------------------------

_______________________________________________
wtp-dev mailing list
[email protected]
https://dev.eclipse.org/mailman/listinfo/wtp-dev
_______________________________________________
wtp-dev mailing list
[email protected]
https://dev.eclipse.org/mailman/listinfo/wtp-dev

Reply via email to