Last week we fixed a bug in 3.0.1 where Dali was not closing
InputStreams (bug 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
jsholl@xxxxxxxxxx
919-543-0011 (t/l 441-0011)
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.
*
*
@author
Kiril
Mitov
k.mitov@xxxxxxx
*
*/
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:
wtp-dev-bounces@xxxxxxxxxxx
[mailto:wtp-dev-bounces@xxxxxxxxxxx] On Behalf Of David M
Williams
Sent: Friday, 1. February 2008 10:16
To: wtp-dev@xxxxxxxxxxx
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.
*
@param project
*
@throws CoreException
*
@throws 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
wtp-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/wtp-dev
_______________________________________________
wtp-dev mailing list
wtp-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/wtp-dev
|