Improve error reporting. New error page that gives a bit more of an explanation...
authorChris Jaekl <cejaekl@yahoo.com>
Mon, 22 Dec 2014 04:13:24 +0000 (23:13 -0500)
committerChris Jaekl <cejaekl@yahoo.com>
Mon, 22 Dec 2014 04:13:24 +0000 (23:13 -0500)
12 files changed:
WEB-INF/classes/frank.properties
prod/frank.properties
prod/net/jaekl/frank/ErrorHandler.java [new file with mode: 0644]
prod/net/jaekl/frank/FrankBundle.java
prod/net/jaekl/frank/Schedule.java
prod/net/jaekl/frank/Style.java [new file with mode: 0644]
prod/net/jaekl/frank/ViewSchedule.java
prod/net/jaekl/qd/http/InvalidResponseException.java
test/net/jaekl/frank/ErrorHandlerTest.java [new file with mode: 0644]
test/net/jaekl/frank/ScheduleTest.java
test/net/jaekl/frank/StyleTest.java [new file with mode: 0644]
test/net/jaekl/frank/ViewScheduleTest.java

index e508d3f1dcaa1913251bcc4d4c06adc1920d545a..4f35303a61c3ecd4797057d05ae54473a1328d8e 100644 (file)
@@ -1,3 +1,4 @@
+answer.received=Answer received:
 data.collected=Data collected <SPAN ID="elapsed">0m 0s</SPAN> ago at {0}.
 destination=Destination
 error.page=Error Page
@@ -5,8 +6,13 @@ eta=ETA
 frank=Frank
 gps.off=GPS off
 gps.read=GPS Read
+invalid.response=Frank requested information from the OC Transpo server, but received an unexpected response.
 m=m
+maybe.server.problem=This may indicate a problem with the server that was contacted, but it is also possible that you've uncovered a bug in Frank.
 remain=Remain
+request.made=Request made:
 route=Route
 s=s
 unexpected.error=Unexpected Error
+unexpected.exception=An unexpected exception has been raised.  This probably indicates a bug in Frank.
+url.contacted=URL contacted:
index e508d3f1dcaa1913251bcc4d4c06adc1920d545a..4f35303a61c3ecd4797057d05ae54473a1328d8e 100644 (file)
@@ -1,3 +1,4 @@
+answer.received=Answer received:
 data.collected=Data collected <SPAN ID="elapsed">0m 0s</SPAN> ago at {0}.
 destination=Destination
 error.page=Error Page
@@ -5,8 +6,13 @@ eta=ETA
 frank=Frank
 gps.off=GPS off
 gps.read=GPS Read
+invalid.response=Frank requested information from the OC Transpo server, but received an unexpected response.
 m=m
+maybe.server.problem=This may indicate a problem with the server that was contacted, but it is also possible that you've uncovered a bug in Frank.
 remain=Remain
+request.made=Request made:
 route=Route
 s=s
 unexpected.error=Unexpected Error
+unexpected.exception=An unexpected exception has been raised.  This probably indicates a bug in Frank.
+url.contacted=URL contacted:
diff --git a/prod/net/jaekl/frank/ErrorHandler.java b/prod/net/jaekl/frank/ErrorHandler.java
new file mode 100644 (file)
index 0000000..c1d72bd
--- /dev/null
@@ -0,0 +1,105 @@
+package net.jaekl.frank;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import net.jaekl.qd.http.InvalidResponseException;
+
+public class ErrorHandler {
+       static final String JAVASCRIPT =
+                       "<SCRIPT>\n" +
+                       "  var show_hide = function() {\n" +
+                       "  var theDiv = document.getElementById('details');\n" +
+                       "  var theButton = document.getElementById('details_btn');\n" +
+                       "  if (theDiv.style.display === 'block' || theDiv.style.display === '') {\n" +
+                       "    theDiv.style.display = 'none';\n" +
+                       "  theButton.value = 'Show details';\n" +
+                       "  }\n" +
+                       "  else {\n" +
+                       "    theDiv.style.display = 'block';\n" +
+                       "    theButton.value = 'Hide details';\n" +
+                       "  }\n" +
+                       "}\n" +
+                       "</SCRIPT>";
+       
+       void writeScript(PrintWriter pw) {
+               pw.println(JAVASCRIPT);
+       }
+       
+       void explain(PrintWriter pw, Throwable t, FrankBundle bundle) {
+               Throwable cause = t;
+               if (t instanceof FrankException) {
+                       if (null != t.getCause()) {
+                               cause = t.getCause();
+                       }
+               }
+               
+               pw.println("<P>");
+               if (cause instanceof InvalidResponseException) {
+                       InvalidResponseException ire = (InvalidResponseException)cause;
+                       
+                       pw.println(bundle.get(FrankBundle.INVALID_RESPONSE));
+                       pw.println("<P ID=\"errtable\">");
+                       pw.println("  <TABLE>");
+                       pw.println("    <TR><TD CLASS=\"head\">" + bundle.get(FrankBundle.URL_CONTACTED) 
+                                       + "</TD><TD>" + ire.getUrl() + "</TD></TR>");
+                       pw.println("    <TR CLASS=\"alt\"><TD CLASS=\"head\">" + bundle.get(FrankBundle.REQUEST_MADE) 
+                                       + "</TD><TD>" + ire.getMethod() + "</TD></TR>");
+                       pw.println("    <TR><TD CLASS=\"head\">" + bundle.get(FrankBundle.ANSWER_RECEIVED) 
+                                       + "</TD><TD>" + ire.getResponse() + "</TD></TR>");
+                       pw.println("  </TABLE>");
+                       pw.println("</P>");
+                       pw.println("<P>" + bundle.get(FrankBundle.MAYBE_SERVER_PROBLEM) + "</P>");
+               }
+               else {
+                       pw.println(bundle.get(FrankBundle.UNEXPECTED_EXCEPTION));
+               }
+               pw.println("</P>");
+       }
+       
+       void writeErrorPage(PrintWriter pw, Throwable t, Locale locale) {
+               Style style = new Style();
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               PrintStream ps = new PrintStream(baos);
+               FrankBundle bundle = FrankBundle.getInst(locale);
+               
+               pw.println("<HTML><HEAD>");
+               pw.println("<TITLE>" + 
+                               bundle.get(FrankBundle.FRANK) + ": " +
+                               bundle.get(FrankBundle.ERROR_PAGE) + 
+                               "</TITLE>");
+               style.writeStyle(pw);
+               writeScript(pw);
+               pw.println("</HEAD>");
+               
+               pw.println("<BODY>");
+               pw.println("<TABLE ID=\"errhead\" WIDTH=\"100%\"><TR><TD>" +
+                               bundle.get(FrankBundle.FRANK) + ": " +
+                               bundle.get(FrankBundle.UNEXPECTED_ERROR) + 
+                               "</TD></TR></TABLE>");
+               
+               explain(pw, t, bundle);
+               
+               // Note that, if we cared about security, we would log this stack trace to a
+               // server log, and only report a cross-reference to the log file back to the 
+               // end user's browser, to avoid potentially exposing internal info that we 
+               // don't want to share.
+               // At least at this point, we don't care (that much), and trade off a 
+               // potential information leak in favour of reducing our code complexity
+               // and the administrator's workload.
+               
+               pw.println("<P><INPUT TYPE=\"button\" ID=\"details_btn\" VALUE=\"Show details\" ONCLICK=\"show_hide();\"/></P>");
+               pw.println("<P>");
+               pw.println("<DIV ID=\"details\" STYLE=\"display: none;\"><PRE>");
+               
+               t.printStackTrace(ps);
+               String stackTrace = baos.toString(); 
+               pw.println(stackTrace);
+                               
+               pw.println("</PRE>\n</P>\n</DIV>");
+               pw.println("<P>Click <A HREF=\"/\">here</A> to return to the main page.</P>");
+               pw.println("</BODY></HTML>");
+       }
+}
index f0889ba1e519b342459105cd6bf8b37511fc95cd..8d5057a9092775535e76b4c4de6d279da10c3841 100644 (file)
@@ -8,6 +8,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import net.jaekl.qd.QDBundleFactory;
 
 public class FrankBundle {
+       public static final String ANSWER_RECEIVED = "answer.received";
        public static final String DATA_COLLECTED = "data.collected";
        public static final String DESTINATION = "destination";
        public static final String ERROR_PAGE = "error.page";
@@ -15,11 +16,16 @@ public class FrankBundle {
        public static final String FRANK = "frank";
        public static final String GPS_OFF = "gps.off";
        public static final String GPS_READ = "gps.read";
+       public static final String INVALID_RESPONSE = "invalid.response";
+       public static final String MAYBE_SERVER_PROBLEM = "maybe.server.problem";
        public static final String MINUTES = "m";       // suffix (abbreviated) for minutes
        public static final String REMAIN = "remain";
+       public static final String REQUEST_MADE = "request.made";
        public static final String ROUTE = "route";
        public static final String SECONDS = "s";
        public static final String UNEXPECTED_ERROR = "unexpected.error";
+       public static final String UNEXPECTED_EXCEPTION = "unexpected.exception";
+       public static final String URL_CONTACTED = "url.contacted";
        
        final static String BUNDLE_NAME = "frank";
        
index edd1b398a602afff7e23aa734d892ee5de6c8a1f..10616b23007608c5802fb4989ee61dbf8408295e 100644 (file)
@@ -13,13 +13,15 @@ import net.jaekl.frank.octranspo.StopInfo;
 import net.jaekl.frank.octranspo.Trip;
 
 public class Schedule {
-       Locale m_locale;
-       FrankBundle m_bundle;
        DateFormat m_hourMinFmt;
        DateFormat m_hourMinSecFmt;
+       FrankBundle m_bundle;
+       Locale m_locale;
+       Style m_style;
        
        public Schedule(Locale locale) {
                m_locale = locale;
+               m_style = new Style();
                m_bundle = FrankBundle.getInst(locale);
                m_hourMinFmt = new SimpleDateFormat("hh:mma", locale);
                m_hourMinSecFmt = new SimpleDateFormat("hh:mm:ssa", locale);
@@ -40,17 +42,7 @@ public class Schedule {
        String mapUrl(double latitude, double longitude) {
                return "http://www.openstreetmap.org/?mlat=" + latitude + "&mlon=" + longitude + "&zoom=15";
        }
-       
-       void writeStyle(PrintWriter pw) {
-               pw.println("<STYLE>");
-               pw.println("  body {background-color: #F0F0C0; font-size: 1.5em; }");
-               pw.println("  #trips {border-collapse: collapse; font-size: 1.5em; }");
-               pw.println("  #trips td, #trips th {border: 1px solid #600000; padding: 3px 3px 3px 3px; text-align: center;}");
-               pw.println("  #trips th {background-color: #800000; color: #FFFFFF; }");
-               pw.println("  #trips tr.ghost td {background-color: #C0C0C0;}");
-               pw.println("</STYLE>");
-       }
-       
+
        // Countdown timer that updates time remaining until each bus is expected.
        void writeScript(PrintWriter pw, String remainArray, int remainCount) {
                String min = trans(FrankBundle.MINUTES);
@@ -82,7 +74,7 @@ public class Schedule {
                pw.println("<HTML>");
                pw.println("<HEAD>");
                pw.println("<TITLE>" + title + "</TITLE>");
-               writeStyle(pw);
+               new Style().writeStyle(pw);
                pw.println("</HEAD>");
        }
        
diff --git a/prod/net/jaekl/frank/Style.java b/prod/net/jaekl/frank/Style.java
new file mode 100644 (file)
index 0000000..f3d58a9
--- /dev/null
@@ -0,0 +1,23 @@
+package net.jaekl.frank;
+
+import java.io.PrintWriter;
+
+public class Style {
+       static final String CSS = 
+                       "<STYLE>\n" +
+                       "  body {background-color: #F0F0C0; font-size: 1em; }\n" +
+                       "  #errhead td {background-color: #D00000; color: #FFFFFF; font-size: 2em; padding: 3px 3px 3px 3px; text-align: left; }\n" +
+                       "  #errtable table { border: 3px solid #D00000; border-collapse: collapse; background-color: #E0E080; }\n" +
+                       "  #errtable table, tr, td { padding: 3px; }\n" +
+                       "  #errtable tr.alt { background-color: #D0D070; }\n" +
+                       "  #errtable td.head {text-align: right; background-color: #D00000; color: #FFFFFF; font-weight: bold; }\n" +
+                       "  #trips {border-collapse: collapse; font-size: 1.5em; }\n" +
+                       "  #trips td, #trips th {border: 1px solid #600000; padding: 3px 3px 3px 3px; text-align: center;}\n" +
+                       "  #trips th {background-color: #800000; color: #FFFFFF; }\n" +
+                       "  #trips tr.ghost td {background-color: #C0C0C0;}\n" +
+                       "</STYLE>";
+       
+       public void writeStyle(PrintWriter pw) {
+               pw.println(CSS);
+       }
+}
index e044f70ba21fa8a47cdaccad421a9384a5ccc856..b13258b3a8ce66227652ee6880886823601528ce 100644 (file)
@@ -1,9 +1,7 @@
 package net.jaekl.frank;
 
-import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.util.Locale;
 
@@ -24,6 +22,12 @@ public class ViewSchedule extends HttpServlet {
        static final String ROUTE = "route";
        static final String LANG = "lang";
        
+       ErrorHandler m_errorHandler;
+       
+       public ViewSchedule() {
+               m_errorHandler = new ErrorHandler();
+       }
+       
        int getParamInt(HttpServletRequest req, String paramName) {
                String valueStr = getParamString(req, paramName);
                try {
@@ -88,38 +92,7 @@ public class ViewSchedule extends HttpServlet {
                        }
                }
                catch (Throwable t) {
-                       writeErrorPage(pw, t, locale);
+                       m_errorHandler.writeErrorPage(pw, t, locale);
                }
        }
-       
-       void writeErrorPage(PrintWriter pw, Throwable t, Locale locale) {
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               PrintStream ps = new PrintStream(baos);
-               FrankBundle bundle = FrankBundle.getInst(locale);
-               
-               pw.println("<HTML><HEAD><TITLE>" + 
-                               bundle.get(FrankBundle.FRANK) + ": " +
-                               bundle.get(FrankBundle.ERROR_PAGE) + 
-                               "</TITLE></HEAD>");
-               pw.println("<BODY><H1>" +
-                               bundle.get(FrankBundle.FRANK) + ": " +
-                               bundle.get(FrankBundle.UNEXPECTED_ERROR) + 
-                               "</H1><P><PRE>");
-
-               // Note that, if we cared about security, we would log this stack trace to a
-               // server log, and only report a cross-reference to the log file back to the 
-               // end user's browser, to avoid potentially exposing internal info that we 
-               // don't want to share.
-               // At least at this point, we don't care (that much), and trade off a 
-               // potential information leak in favour of reducing our code complexity
-               // and the administrator's workload.
-               t.printStackTrace(ps);
-               String stackTrace = baos.toString(); 
-               pw.println(stackTrace);
-                               
-               pw.println("</PRE></P></BODY>");
-               pw.println("</HTML>");
-       }
-       
-
 }
index 7d0bdc85d8a21c5bff5c9877d7f9b820883fb874..5240f15d95625ea8d1b31d5da38ddcae11306672 100644 (file)
@@ -19,6 +19,7 @@ public class InvalidResponseException extends QDException {
        
        public String getUrl() { return m_url; }
        public String getMethod() { return m_method; }
+       public String getResponse() { return m_response; }
        
        @Override
        public String toString() {
diff --git a/test/net/jaekl/frank/ErrorHandlerTest.java b/test/net/jaekl/frank/ErrorHandlerTest.java
new file mode 100644 (file)
index 0000000..4db0602
--- /dev/null
@@ -0,0 +1,102 @@
+package net.jaekl.frank;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+import java.util.Locale;
+
+import net.jaekl.qd.QDException;
+import net.jaekl.qd.http.InvalidResponseException;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ErrorHandlerTest {
+       static final String GATEWAY = "http://www.jaekl.net/api";
+       static final String METHOD = "SampleApiMethod";
+       static final String RESPONSE = "Required parameter not specified.";
+       
+       ByteArrayOutputStream m_baos;
+       PrintWriter m_pw;
+       
+       @Before
+       public void setUp() {
+               m_baos = new ByteArrayOutputStream();
+               m_pw = new PrintWriter(m_baos);
+       }
+       
+       @After
+       public void tearDown() throws IOException {
+               m_pw.close();
+       }
+       
+       @Test
+       public void testWriteErrorPage_basicBehaviourWithVariousExceptions() {
+               ErrorHandler eh = new ErrorHandler();
+               
+               Throwable[] throwables = { 
+                               new NullPointerException(),
+                               new QDException(),
+                               new SQLException(),
+                               new InvalidResponseException(new NullPointerException(), GATEWAY, METHOD, RESPONSE)
+               };
+               
+               for (Throwable t : throwables) {
+                       m_baos.reset();
+                       eh.writeErrorPage(m_pw, t, Locale.CANADA);
+                       m_pw.flush();
+                       
+                       String actual = m_baos.toString();
+                       Assert.assertTrue(actual.contains("<TITLE>Frank: Error Page</TITLE>"));
+                       Assert.assertTrue(actual.contains(t.toString()));
+               }
+       }
+       
+       @Test
+       public void testExplain_unexpectedException() {
+               Locale[] locales = { Locale.CANADA, Locale.FRANCE, Locale.JAPAN, Locale.CHINA};
+               
+               ErrorHandler eh = new ErrorHandler();
+               
+               for (Locale locale : locales) {
+                       FrankBundle bundle = FrankBundle.getInst(locale);
+                       
+                       m_baos.reset();
+                       eh.writeErrorPage(m_pw, new NullPointerException(),  Locale.CANADA);
+                       m_pw.flush();
+                       
+                       String actual = m_baos.toString();
+                       Assert.assertTrue(actual.contains(bundle.get(FrankBundle.UNEXPECTED_EXCEPTION)));
+               }
+       }
+       
+       @Test
+       public void testExplain_wrappedInvalidResponseException() {
+               Locale[] locales = { Locale.CANADA, Locale.FRANCE, Locale.JAPAN, Locale.CHINA};
+               
+               ErrorHandler eh = new ErrorHandler();
+               InvalidResponseException ire = new InvalidResponseException(null, GATEWAY, METHOD, RESPONSE);
+               FrankException fe = new FrankException(ire);
+               
+               for (Locale locale : locales) {
+                       FrankBundle bundle = FrankBundle.getInst(locale);
+                       
+                       m_baos.reset();
+                       eh.writeErrorPage(m_pw, fe,  Locale.CANADA);
+                       m_pw.flush();
+                       
+                       String actual = m_baos.toString();
+                       
+                       Assert.assertTrue(actual.contains(bundle.get(FrankBundle.INVALID_RESPONSE)));
+                       
+                       Assert.assertTrue(actual.contains(bundle.get(FrankBundle.URL_CONTACTED)));
+                       Assert.assertTrue(actual.contains(bundle.get(FrankBundle.REQUEST_MADE)));
+                       Assert.assertTrue(actual.contains(bundle.get(FrankBundle.ANSWER_RECEIVED)));
+                       
+                       Assert.assertTrue(actual.contains(bundle.get(FrankBundle.MAYBE_SERVER_PROBLEM)));
+               }
+       }
+}
index 2fc9ac2a5f84f09bf189840648f0b3fb7df50ede..7f3068031af593085b2819f870a2fa6acefbfea7 100644 (file)
@@ -17,15 +17,8 @@ import org.junit.Before;
 import org.junit.Test;
 
 public class ScheduleTest {
-       static final String EXPECTED_STYLE = "<STYLE>\n" + 
-                       "  body {background-color: #F0F0C0; font-size: 1.5em; }\n" + 
-                       "  #trips {border-collapse: collapse; font-size: 1.5em; }\n" + 
-                       "  #trips td, #trips th {border: 1px solid #600000; padding: 3px 3px 3px 3px; text-align: center;}\n" + 
-                       "  #trips th {background-color: #800000; color: #FFFFFF; }\n" + 
-                       "  #trips tr.ghost td {background-color: #C0C0C0;}\n" + 
-                       "</STYLE>\n";
        static final String TITLE_PREFIX = "<HTML>\n<HEAD>\n<TITLE>";
-       static final String TITLE_SUFFIX = "</TITLE>\n" + EXPECTED_STYLE + "</HEAD>\n";
+       static final String TITLE_SUFFIX = "</TITLE>\n" + Style.CSS + "\n</HEAD>\n";
        
        
        ByteArrayOutputStream m_baos;
@@ -44,25 +37,6 @@ public class ScheduleTest {
                }
        }
        
-       // Confirm that writeStyle's output does not vary with the locale
-       @Test
-       public void test_writeStyle() {
-               String actual;
-
-               Locale[] locales = { Locale.CANADA, Locale.CANADA_FRENCH, Locale.JAPAN };
-               
-               for (Locale locale : locales) {
-                       m_baos.reset();
-                       
-                       Schedule schedule = new Schedule(locale);
-                       schedule.writeStyle(m_pw);
-                       m_pw.flush();
-                       
-                       actual = m_baos.toString();
-                       Assert.assertEquals(EXPECTED_STYLE, actual);
-               }
-       }
-       
        @Test
        public void test_writeHeader() {
                Locale[] locales = { Locale.CANADA, Locale.CANADA_FRENCH, Locale.JAPAN };
@@ -102,7 +76,7 @@ public class ScheduleTest {
                
                String actual = m_baos.toString();
                
-               Assert.assertTrue(actual.contains(EXPECTED_STYLE));
+               Assert.assertTrue(actual.contains(Style.CSS));
                
                String expectedTitle = TITLE_PREFIX + "Frank: " + stopName + " (" + stopNo + ")" + TITLE_SUFFIX;
                Assert.assertTrue(actual.contains(expectedTitle));
@@ -178,7 +152,7 @@ public class ScheduleTest {
                
                // Some rudimentary validation of the result.
                // Should really go through more permutations, and examine them more closely, here.
-               Assert.assertTrue(actual.contains(EXPECTED_STYLE));
+               Assert.assertTrue(actual.contains(Style.CSS));
                
                String expectedTitle = TITLE_PREFIX + "Frank: " + stopName + " (" + stopNo + ")" + TITLE_SUFFIX;
                Assert.assertTrue(actual.contains(expectedTitle));
diff --git a/test/net/jaekl/frank/StyleTest.java b/test/net/jaekl/frank/StyleTest.java
new file mode 100644 (file)
index 0000000..f08f649
--- /dev/null
@@ -0,0 +1,45 @@
+package net.jaekl.frank;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class StyleTest {
+       ByteArrayOutputStream m_baos;
+       PrintWriter m_pw;
+       
+       @Before
+       public void setUp() {
+               m_baos = new ByteArrayOutputStream();
+               m_pw = new PrintWriter(m_baos);
+       }
+       
+       @After
+       public void tearDown() throws IOException {
+               if (null != m_baos) {
+                       m_baos.close();
+               }
+       }
+       
+       // Should develop something here that is a bit smarter about what 
+       // it's looking for, and less brittle than a simple compare-against-master...
+       @Test
+       public void test_writeStyle() {
+               String actual;
+
+               m_baos.reset();
+               
+               Style style = new Style();
+               style.writeStyle(m_pw);
+               m_pw.flush();
+               
+               actual = m_baos.toString();
+               Assert.assertEquals(Style.CSS + "\n", actual);
+       }
+}
index eec671f55829ac0156ee573152ab12b67f3a8606..673b34303f6e9edf508bbfb3bdc132c3f97cfd07 100644 (file)
@@ -1,12 +1,7 @@
 package net.jaekl.frank;
 
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-import java.sql.SQLException;
 import java.util.HashMap;
-import java.util.Locale;
 
-import net.jaekl.qd.QDException;
 import net.jaekl.qd.http.HttpServletRequestMock;
 
 import org.junit.Assert;
@@ -72,29 +67,4 @@ public class ViewScheduleTest {
                value = vs.getParamString(reqMock, "notPresent");
                Assert.assertEquals(null, value);
        }
-
-       @Test
-       public void testWriteErrorPage() {
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               PrintWriter pw = new PrintWriter(baos);
-               
-               ViewSchedule vs = new ViewSchedule();
-               
-               Throwable[] throwables = { 
-                               new NullPointerException(),
-                               new QDException(),
-                               new SQLException()
-               };
-               
-               for (Throwable t : throwables) {
-                       baos.reset();
-                       vs.writeErrorPage(pw, t, Locale.CANADA);        // TODO:  test translations
-                       pw.flush();
-                       
-                       String actual = baos.toString();
-                       Assert.assertTrue(actual.contains("<TITLE>Frank: Error Page</TITLE>"));
-                       Assert.assertTrue(actual.contains(t.toString()));
-               }
-       }
-
 }