1 /* 2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.debug.test; 26 27 import static org.graalvm.compiler.debug.DebugContext.NO_DESCRIPTION; 28 import static org.graalvm.compiler.debug.DebugContext.NO_GLOBAL_METRIC_VALUES; 29 30 import java.io.ByteArrayOutputStream; 31 import java.io.DataInputStream; 32 import java.io.IOException; 33 import java.io.PrintStream; 34 import java.util.Arrays; 35 import java.util.Collections; 36 import java.util.Formatter; 37 import java.util.List; 38 39 import jdk.internal.vm.compiler.collections.EconomicMap; 40 import org.graalvm.compiler.debug.Assertions; 41 import org.graalvm.compiler.debug.CounterKey; 42 import org.graalvm.compiler.debug.DebugCloseable; 43 import org.graalvm.compiler.debug.DebugContext; 44 import org.graalvm.compiler.debug.DebugContext.Scope; 45 import org.graalvm.compiler.debug.DebugDumpHandler; 46 import org.graalvm.compiler.debug.DebugHandler; 47 import org.graalvm.compiler.debug.DebugHandlersFactory; 48 import org.graalvm.compiler.debug.DebugOptions; 49 import org.graalvm.compiler.debug.DebugVerifyHandler; 50 import org.graalvm.compiler.options.OptionKey; 51 import org.graalvm.compiler.options.OptionValues; 52 import org.junit.Assert; 53 import org.junit.Assume; 54 import org.junit.Test; 55 56 @SuppressWarnings("try") 57 public class DebugContextTest { 58 59 static class DebugContextSetup { 60 final Formatter dumpOutput = new Formatter(); 61 final Formatter verifyOutput = new Formatter(); 62 final ByteArrayOutputStream logOutput = new ByteArrayOutputStream(); 63 DebugHandlersFactory handlers = new DebugHandlersFactory() { 64 @Override 65 public List<DebugHandler> createHandlers(OptionValues options) { 66 return Arrays.asList(new DebugDumpHandler() { 67 @Override 68 public void dump(DebugContext ignore, Object object, String format, Object... arguments) { 69 dumpOutput.format("Dumping %s with label \"%s\"%n", object, String.format(format, arguments)); 70 } 71 }, new DebugVerifyHandler() { 72 @Override 73 public void verify(DebugContext ignore, Object object, String format, Object... args) { 74 verifyOutput.format("Verifying %s with label \"%s\"%n", object, String.format(format, args)); 75 } 76 }); 77 } 78 }; 79 openDebugContext(OptionValues options)80 DebugContext openDebugContext(OptionValues options) { 81 return DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(logOutput), Collections.singletonList(handlers)); 82 83 } 84 } 85 86 @Test testDisabledScopes()87 public void testDisabledScopes() { 88 OptionValues options = new OptionValues(EconomicMap.create()); 89 DebugContextSetup setup = new DebugContextSetup(); 90 try (DebugContext debug = setup.openDebugContext(options); 91 DebugContext.Scope d = debug.scope("TestDisabledScoping")) { 92 for (int level = DebugContext.BASIC_LEVEL; level <= DebugContext.VERY_DETAILED_LEVEL; level++) { 93 debug.dump(level, "an object", "at level %d", level); 94 debug.verify("an object", "at level %d", level); 95 debug.log(level, "log statement at level %d", level); 96 } 97 } 98 String log = setup.logOutput.toString(); 99 String dumpOutput = setup.dumpOutput.toString(); 100 String verifyOutput = setup.verifyOutput.toString(); 101 Assert.assertTrue(log, log.isEmpty()); 102 Assert.assertTrue(dumpOutput, dumpOutput.isEmpty()); 103 Assert.assertTrue(verifyOutput, verifyOutput.isEmpty()); 104 } 105 106 @Test testDumping()107 public void testDumping() { 108 for (int level = DebugContext.BASIC_LEVEL; level <= DebugContext.VERY_DETAILED_LEVEL; level++) { 109 OptionValues options = new OptionValues(EconomicMap.create()); 110 options = new OptionValues(options, DebugOptions.Dump, "Scope" + level + ":" + level); 111 DebugContextSetup setup = new DebugContextSetup(); 112 try (DebugContext debug = setup.openDebugContext(options); 113 DebugContext.Scope s0 = debug.scope("TestDumping")) { 114 try (DebugContext.Scope s1 = debug.scope("Scope1")) { 115 try (DebugContext.Scope s2 = debug.scope("Scope2")) { 116 try (DebugContext.Scope s3 = debug.scope("Scope3")) { 117 try (DebugContext.Scope s4 = debug.scope("Scope4")) { 118 try (DebugContext.Scope s5 = debug.scope("Scope5")) { 119 debug.dump(level, "an object", "at level %d", level); 120 } 121 } 122 } 123 } 124 } 125 126 } 127 128 String expect = String.format("Dumping an object with label \"at level %d\"%n", level); 129 String dump = setup.dumpOutput.toString(); 130 Assert.assertEquals(expect, dump); 131 } 132 } 133 134 @Test testLogging()135 public void testLogging() throws IOException { 136 OptionValues options = new OptionValues(EconomicMap.create()); 137 options = new OptionValues(options, DebugOptions.Log, ":5"); 138 DebugContextSetup setup = new DebugContextSetup(); 139 try (DebugContext debug = setup.openDebugContext(options)) { 140 for (int level = DebugContext.BASIC_LEVEL; level <= DebugContext.VERY_DETAILED_LEVEL; level++) { 141 try (DebugContext.Scope s0 = debug.scope("TestLogging")) { 142 debug.log(level, "log statement at level %d", level); 143 try (DebugContext.Scope s1 = debug.scope("Level1")) { 144 debug.log(level, "log statement at level %d", level); 145 try (DebugContext.Scope s2 = debug.scope("Level2")) { 146 debug.log(level, "log statement at level %d", level); 147 try (DebugContext.Scope s3 = debug.scope("Level3")) { 148 debug.log(level, "log statement at level %d", level); 149 try (DebugContext.Scope s4 = debug.scope("Level4")) { 150 debug.log(level, "log statement at level %d", level); 151 try (DebugContext.Scope s5 = debug.scope("Level5")) { 152 debug.log(level, "log statement at level %d", level); 153 } 154 } 155 } 156 } 157 } 158 } 159 } 160 } 161 DataInputStream in = new DataInputStream(getClass().getResourceAsStream(getClass().getSimpleName() + ".testLogging.input")); 162 byte[] buf = new byte[in.available()]; 163 in.readFully(buf); 164 String threadLabel = "[thread:" + Thread.currentThread().getId() + "]"; 165 String expect = new String(buf).replace("[thread:1]", threadLabel); 166 167 String log = setup.logOutput.toString(); 168 Assert.assertEquals(expect, log); 169 } 170 171 @Test testContextScope()172 public void testContextScope() { 173 OptionValues options = new OptionValues(EconomicMap.create()); 174 options = new OptionValues(options, DebugOptions.Log, ":5"); 175 DebugContextSetup setup = new DebugContextSetup(); 176 try (DebugContext debug = setup.openDebugContext(options)) { 177 try (DebugContext.Scope s0 = debug.scope("TestLogging")) { 178 try (DebugContext.Scope s1 = debug.withContext("A")) { 179 for (Object o : debug.context()) { 180 Assert.assertEquals(o, "A"); 181 } 182 } catch (Throwable t) { 183 throw debug.handle(t); 184 } 185 try (DebugContext.Scope s1 = debug.withContext("B")) { 186 for (Object o : debug.context()) { 187 Assert.assertEquals(o, "B"); 188 } 189 } catch (Throwable t) { 190 throw debug.handle(t); 191 } 192 } 193 } 194 195 } 196 197 @Test testEnabledSandbox()198 public void testEnabledSandbox() { 199 EconomicMap<OptionKey<?>, Object> map = EconomicMap.create(); 200 // Configure with an option that enables scopes 201 map.put(DebugOptions.DumpOnError, true); 202 OptionValues options = new OptionValues(map); 203 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 204 DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(baos), DebugHandlersFactory.LOADER); 205 Exception e = new Exception("testEnabledSandbox"); 206 String scopeName = ""; 207 try { 208 try (DebugContext.Scope d = debug.sandbox("TestExceptionHandling", debug.getConfig())) { 209 scopeName = d.getQualifiedName(); 210 throw e; 211 } catch (Throwable t) { 212 assert e == t; 213 debug.handle(t); 214 } 215 } catch (Throwable t) { 216 // The exception object should propagate all the way out through 217 // a enabled sandbox scope 218 Assert.assertEquals(e, t); 219 } 220 String logged = baos.toString(); 221 String expected = String.format("Exception raised in scope %s: %s", scopeName, e); 222 String line = "-------------------------------------------------------"; 223 Assert.assertTrue(String.format("Could not find \"%s\" in content between lines below:%n%s%n%s%s", expected, line, logged, line), logged.contains(expected)); 224 } 225 226 @Test testDisabledSandbox()227 public void testDisabledSandbox() { 228 EconomicMap<OptionKey<?>, Object> map = EconomicMap.create(); 229 // Configure with an option that enables scopes 230 map.put(DebugOptions.DumpOnError, true); 231 OptionValues options = new OptionValues(map); 232 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 233 DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(baos), DebugHandlersFactory.LOADER); 234 Exception e = new Exception("testDisabledSandbox"); 235 try { 236 // Test a disabled sandbox scope 237 try (DebugContext.Scope d = debug.sandbox("TestExceptionHandling", null)) { 238 throw e; 239 } catch (Throwable t) { 240 assert e == t; 241 debug.handle(t); 242 } 243 } catch (Throwable t) { 244 // The exception object should propagate all the way out through 245 // a disabled sandbox scope 246 Assert.assertEquals(e, t); 247 } 248 String logged = baos.toString(); 249 Assert.assertTrue(logged, logged.isEmpty()); 250 } 251 252 /** 253 * Tests that using a {@link DebugContext} on a thread other than the one on which it was 254 * created causes an assertion failure. 255 */ 256 @Test testInvariantChecking()257 public void testInvariantChecking() throws InterruptedException { 258 Assume.assumeTrue(Assertions.assertionsEnabled()); 259 EconomicMap<OptionKey<?>, Object> map = EconomicMap.create(); 260 // Configure with an option that enables counters 261 map.put(DebugOptions.Counters, ""); 262 OptionValues options = new OptionValues(map); 263 DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER); 264 CounterKey counter = DebugContext.counter("DebugContextTestCounter"); 265 AssertionError[] result = {null}; 266 Thread thread = new Thread() { 267 268 @Override 269 public void run() { 270 try { 271 counter.add(debug, 1); 272 } catch (AssertionError e) { 273 result[0] = e; 274 } 275 } 276 }; 277 thread.start(); 278 thread.join(); 279 280 Assert.assertNotNull("Expected thread to throw AssertionError", result[0]); 281 } 282 283 @Test testDisableIntercept()284 public void testDisableIntercept() { 285 EconomicMap<OptionKey<?>, Object> map = EconomicMap.create(); 286 // Configure with an option that enables scopes 287 map.put(DebugOptions.DumpOnError, true); 288 OptionValues options = new OptionValues(map); 289 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 290 DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(baos), DebugHandlersFactory.LOADER); 291 Exception e = new Exception(); 292 try { 293 try (DebugCloseable disabled = debug.disableIntercept(); Scope s1 = debug.scope("ScopeWithDisabledIntercept")) { 294 try (Scope s2 = debug.scope("InnerScopeInheritsDisabledIntercept")) { 295 throw e; 296 } 297 } catch (Throwable t) { 298 assert e == t; 299 debug.handle(t); 300 } 301 } catch (Throwable t) { 302 // The exception object should propagate all the way out through 303 // an intercept disabled scope 304 Assert.assertEquals(e, t); 305 } 306 String logged = baos.toString(); 307 Assert.assertEquals("Exception should not have been intercepted", "", logged); 308 } 309 } 310