blob: c50c69c2595d6b2d90c5b827326d5ebd40ce46d1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.openide;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.regex.Pattern;
import junit.framework.AssertionFailedError;
import junit.framework.TestResult;
import org.netbeans.junit.MockServices;
import org.netbeans.junit.NbTestCase;
import org.openide.util.Lookup;
/** Basic skeleton for logging test case.
*
* @author Jaroslav Tulach
*/
public abstract class LoggingTestCaseHid extends NbTestCase {
static {
MockServices.setServices(new Class[] {ErrManager.class});
}
protected LoggingTestCaseHid (String name) {
super (name);
}
/** If execution fails we wrap the exception with
* new log message.
*/
protected void runTest () throws Throwable {
assertNotNull ("ErrManager has to be in lookup", Lookup.getDefault().lookup(ErrManager.class));
ErrManager.clear(getName(), getLog());
try {
super.runTest ();
} catch (AssertionFailedError ex) {
AssertionFailedError ne = new AssertionFailedError (ex.getMessage () + " Log:\n" + ErrManager.messages);
ne.setStackTrace (ex.getStackTrace ());
throw ne;
} catch (IOException iex) {//#66208
IOException ne = new IOException (iex.getMessage () + " Log:\n" + ErrManager.messages);
ne.setStackTrace (iex.getStackTrace ());
throw ne;
} finally {
// do not write to log files anymore
ErrManager.clear(getName(), System.err);
}
}
/** Registers hints for controlling thread switching in multithreaded
* applications.
* @param url the url to read the file from
* @exception IOException thrown when there is problem reading the url
*/
protected final void registerSwitches(URL url, int timeout) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream is = url.openStream();
for (;;) {
int ch = is.read ();
if (ch == -1) break;
os.write (ch);
}
os.close();
is.close();
registerSwitches(new String(os.toByteArray(), "utf-8"), timeout);
}
/** Registers hints for controlling thread switching in multithreaded
* applications.
*/
protected final void registerSwitches(String order, int timeout) {
ErrManager.timeout = timeout;
LinkedList switches = new LinkedList();
HashMap exprs = new HashMap();
int pos = 0;
for(;;) {
int thr = order.indexOf("THREAD:", pos);
if (thr == -1) {
break;
}
int msg = order.indexOf("MSG:", thr);
if (msg == -1) {
fail("After THREAD: there must be MSG: " + order.substring(thr));
}
int end = order.indexOf("THREAD:", msg);
if (end == -1) {
end = order.length();
}
String thrName = order.substring(pos + 7, msg).trim();
String msgText = order.substring(msg + 4, end).trim();
Pattern p = (Pattern)exprs.get(msgText);
if (p == null) {
p = Pattern.compile(msgText);
exprs.put(msgText, p);
}
Switch s = new Switch(thrName, p);
switches.add(s);
pos = end;
}
ErrManager.switches = switches;
}
//
// Logging support
//
public static final class ErrManager extends ErrorManager {
public static final StringBuffer messages = new StringBuffer ();
static java.io.PrintStream log = System.err;
private String prefix;
private static LinkedList switches;
private static int timeout;
/** maps names of threads to their instances*/
private static java.util.Map threads = new java.util.HashMap();
public ErrManager () {
this (null);
}
public ErrManager (String prefix) {
this.prefix = prefix;
}
public Throwable annotate (Throwable t, int severity, String message, String localizedMessage, Throwable stackTrace, Date date) {
return t;
}
public Throwable attachAnnotations (Throwable t, ErrorManager.Annotation[] arr) {
return t;
}
public ErrorManager.Annotation[] findAnnotations (Throwable t) {
return null;
}
public ErrorManager getInstance (String name) {
if (
true
) {
return new ErrManager ('[' + name + "] ");
} else {
// either new non-logging or myself if I am non-logging
return new ErrManager ();
}
}
public void log (int severity, String s) {
StringBuffer oneMsg = new StringBuffer();
if (prefix != null) {
oneMsg.append(prefix);
} else {
oneMsg.append("[default] ");
}
oneMsg.append("THREAD:");
oneMsg.append(Thread.currentThread().getName());
oneMsg.append(" MSG:");
oneMsg.append(s);
messages.append(oneMsg.toString());
messages.append ('\n');
if (messages.length() > 40000) {
messages.delete(0, 20000);
}
log.println(oneMsg.toString());
if (switches != null) {
boolean log = true;
boolean expectingMsg = false;
for(;;) {
synchronized (switches) {
if (switches.isEmpty()) {
return;
}
Switch w = (Switch)switches.getFirst();
String threadName = Thread.currentThread().getName();
boolean foundMatch = false;
if (w.matchesThread()) {
if (!w.matchesMessage(s)) {
// same thread but wrong message => go on
return;
}
// the correct message from the right thread found
switches.removeFirst();
if (switches.isEmpty()) {
// end of sample, make all run
switches.notifyAll();
return;
}
w = (Switch)switches.getFirst();
if (w.matchesThread()) {
// next message is also from this thread, go on
return;
}
expectingMsg = true;
foundMatch = true;
} else {
// compute whether we shall wait or not
java.util.Iterator it = switches.iterator();
while (it.hasNext()) {
Switch check = (Switch)it.next();
if (check.matchesMessage(s)) {
expectingMsg = true;
break;
}
}
}
// make it other thread run
Thread t = (Thread)threads.get(w.name);
if (t != null) {
if (log) {
messages.append("t: " + threadName + " interrupts: " + t.getName() + "\n");
}
t.interrupt();
}
threads.put(threadName, Thread.currentThread());
//
// if (log) {
// messages.append("t: " + Thread.currentThread().getName() + " log: " + s + " result: " + m + " for: " + w + "\n");
// }
if (!expectingMsg) {
return;
}
// clear any interrupt that happend before
Thread.interrupted();
try {
if (log) {
messages.append("t: " + threadName + " log: " + s + " waiting\n");
}
switches.wait(timeout);
if (log) {
messages.append("t: " + threadName + " log: " + s + " timeout\n");
}
return;
} catch (InterruptedException ex) {
// ok, we love to be interrupted => go on
if (log) {
messages.append("t: " + threadName + " log: " + s + " interrupted\n");
}
if (foundMatch) {
return;
}
}
}
}
}
}
public void notify (int severity, Throwable t) {
log (severity, t.getMessage ());
}
public boolean isNotifiable (int severity) {
return prefix != null;
}
public boolean isLoggable (int severity) {
return prefix != null;
}
private static void clear(String n, PrintStream printStream) {
ErrManager.log = printStream;
ErrManager.messages.setLength(0);
ErrManager.messages.append ("Starting test ");
ErrManager.messages.append (n);
ErrManager.messages.append ('\n');
threads.clear();
}
} // end of ErrManager
private static final class Switch {
private Pattern msg;
private String name;
public Switch(String n, Pattern m) {
this.name = n;
this.msg = m;
}
/** @return true if the thread name of the caller matches this switch
*/
public boolean matchesThread() {
String thr = Thread.currentThread().getName();
return name.equals(thr);
}
/** @return true if the message matches the one provided by this switch
*/
public boolean matchesMessage(String logMsg) {
return msg.matcher(logMsg).matches();
}
public String toString() {
return "Switch[" + name + "]: " + msg;
}
}
}