1 /*
2  * Copyright (c) 2016, 2018, 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  * @test
26  * @bug 8168615
27  * @summary Test that fail-over works for fail-over ExecutionControlProvider
28  * with direct maps.
29  * @modules jdk.compiler/com.sun.tools.javac.api
30  *          jdk.compiler/com.sun.tools.javac.main
31  *          jdk.jdeps/com.sun.tools.javap
32  *          jdk.jshell/jdk.jshell.execution
33  *          jdk.jshell/jdk.jshell.spi
34  * @library /tools/lib
35  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask
36  * @build KullaTesting ExecutionControlTestBase Compiler
37  * @run testng FailOverDirectExecutionControlTest
38  * @key intermittent
39  */
40 
41 import java.nio.file.Path;
42 import java.nio.file.Paths;
43 import java.util.ArrayList;
44 import java.util.HashMap;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.logging.Handler;
48 import java.util.logging.Level;
49 import java.util.logging.LogRecord;
50 import java.util.logging.Logger;
51 import org.testng.annotations.AfterMethod;
52 import org.testng.annotations.Test;
53 import org.testng.annotations.BeforeMethod;
54 import jdk.jshell.execution.FailOverExecutionControlProvider;
55 import jdk.jshell.spi.ExecutionControlProvider;
56 import static org.testng.Assert.assertEquals;
57 import static org.testng.Assert.assertNull;
58 import static org.testng.Assert.assertTrue;
59 
60 @Test
61 public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase {
62 
63     ClassLoader ccl;
64     ExecutionControlProvider provider;
65     LogTestHandler hndlr;
66     Map<Level, List<String>> logged;
67 
68     private class LogTestHandler extends Handler {
69 
LogTestHandler()70         LogTestHandler() {
71             setLevel(Level.ALL);
72             setFilter(lr -> lr.getLoggerName().equals("jdk.jshell.execution"));
73         }
74 
75         @Override
publish(LogRecord lr)76         public void publish(LogRecord lr) {
77             List<String> l = logged.get(lr.getLevel());
78             if (l == null) {
79                 l = new ArrayList<>();
80                 logged.put(lr.getLevel(), l);
81             }
82             l.add(lr.getMessage());
83         }
84 
85         @Override
flush()86         public void flush() {
87         }
88 
89         @Override
close()90         public void close() throws SecurityException {
91         }
92 
93     }
94 
95     @BeforeMethod
96     @Override
setUp()97     public void setUp() {
98         Logger logger = Logger.getLogger("jdk.jshell.execution");
99         logger.setLevel(Level.ALL);
100         hndlr = new LogTestHandler();
101         logger.addHandler(hndlr);
102         logged = new HashMap<>();
103         Compiler compiler = new Compiler();
104         Path modDir = Paths.get("mod");
105         compiler.compile(modDir,
106                 "package my.provide; import java.util.Map;\n" +
107                 "import jdk.jshell.spi.ExecutionControl;\n" +
108                 "import jdk.jshell.spi.ExecutionControlProvider;\n" +
109                 "import jdk.jshell.spi.ExecutionEnv;\n" +
110                 "public class AlwaysFailingProvider implements ExecutionControlProvider {\n" +
111                 "    @Override\n" +
112                 "    public String name() {\n" +
113                 "        return \"alwaysFailing\";\n" +
114                 "    }\n" +
115                 "    @Override\n" +
116                 "    public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters) throws Throwable {\n" +
117                 "        throw new UnsupportedOperationException(\"This operation intentionally broken.\");\n" +
118                 "    }\n" +
119                 "}\n",
120                 "module my.provide {\n" +
121                 "    requires transitive jdk.jshell;\n" +
122                 "    provides jdk.jshell.spi.ExecutionControlProvider\n" +
123                 "        with my.provide.AlwaysFailingProvider;\n" +
124                 " }");
125         Path modPath = compiler.getPath(modDir);
126         ccl = createAndRunFromModule("my.provide", modPath);
127 
128         provider = new FailOverExecutionControlProvider();
129         Map<String, String> pm = provider.defaultParameters();
130         pm.put("0", "alwaysFailing");
131         pm.put("1", "alwaysFailing");
132         pm.put("2", standardListenSpec());
133         pm.put("3", standardLaunchSpec());
134         pm.put("4", standardJdiSpec());
135         setUp(builder -> builder.executionEngine(provider, pm));
136     }
137 
138     @AfterMethod
139     @Override
tearDown()140     public void tearDown() {
141         super.tearDown();
142         Logger logger = Logger.getLogger("jdk.jshell.execution");
143         logger.removeHandler(hndlr);
144         Thread.currentThread().setContextClassLoader(ccl);
145     }
146 
147     @Override
variables()148     public void variables() {
149         super.variables();
150         assertEquals(logged.get(Level.FINEST).size(), 1);
151         assertEquals(logged.get(Level.FINE).size(), 2);
152         assertEquals(logged.get(Level.WARNING).size(), 2);
153         assertNull(logged.get(Level.SEVERE));
154         String log = logged.get(Level.WARNING).get(0);
155         assertTrue(log.contains("Failure failover -- 0 = alwaysFailing"), log);
156         assertTrue(log.contains("This operation intentionally broken"), log);
157         log = logged.get(Level.WARNING).get(1);
158         assertTrue(log.contains("Failure failover -- 1 = alwaysFailing"), log);
159         assertTrue(log.contains("This operation intentionally broken"), log);
160         log = logged.get(Level.FINEST).get(0);
161         assertTrue(
162                 log.contains("Success failover -- 2 = " + standardListenSpec())
163                 || log.contains("Success failover -- 3 = " + standardLaunchSpec())
164                 || log.contains("Success failover -- 4 = " + standardJdiSpec()),
165                 log);
166     }
167 }
168