1 /*
2  * Copyright (c) 2019, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.jfr.api.consumer.recordingstream;
27 
28 import java.util.concurrent.CountDownLatch;
29 import java.util.concurrent.atomic.AtomicBoolean;
30 import java.util.concurrent.atomic.AtomicInteger;
31 
32 import jdk.jfr.api.consumer.recordingstream.TestUtils.TestError;
33 import jdk.jfr.api.consumer.recordingstream.TestUtils.TestException;
34 import jdk.jfr.api.consumer.security.TestStreamingRemote.TestEvent;
35 import jdk.jfr.consumer.RecordingStream;
36 
37 /**
38  * @test
39  * @summary Tests RecordingStream::onError(...) when using
40  *          RecordingStream:startAsync
41  * @key jfr
42  * @requires vm.hasJFR
43  * @library /test/lib /test/jdk
44  * @run main/othervm jdk.jfr.api.consumer.recordingstream.TestOnErrorAsync
45  */
46 public class TestOnErrorAsync {
main(String... args)47     public static void main(String... args) throws Exception {
48         testDefaultError();
49         testCustomError();
50         testDefaultException();
51         testCustomException();
52         testOnFlushSanity();
53         testOnCloseSanity();
54     }
55 
testDefaultError()56     private static void testDefaultError() throws Exception {
57         AtomicBoolean closed = new AtomicBoolean();
58         CountDownLatch receivedError = new CountDownLatch(1);
59         try (RecordingStream r = new RecordingStream()) {
60             r.onEvent(e -> {
61                 TestError error = new TestError();
62                 TestUtils.installUncaughtException(receivedError, error);
63                 throw error; // closes stream
64             });
65             r.onClose(() -> {
66                 closed.set(true);
67             });
68             r.startAsync();
69             TestEvent e = new TestEvent();
70             e.commit();
71             r.awaitTermination();
72             receivedError.await();
73             if (!closed.get()) {
74                 throw new Exception("Expected stream to be closed");
75             }
76         }
77     }
78 
testCustomError()79     private static void testCustomError() throws Exception {
80         AtomicBoolean onError = new AtomicBoolean();
81         AtomicBoolean closed = new AtomicBoolean();
82         CountDownLatch receivedError = new CountDownLatch(1);
83         try (RecordingStream r = new RecordingStream()) {
84             r.onEvent(e -> {
85                 TestError error = new TestError();
86                 TestUtils.installUncaughtException(receivedError, error);
87                 throw error; // closes stream
88             });
89             r.onError(e -> {
90                 onError.set(true);
91             });
92             r.onClose(() -> {
93                 closed.set(true);
94             });
95             r.startAsync();
96             TestEvent e = new TestEvent();
97             e.commit();
98             r.awaitTermination();
99             receivedError.await();
100             if (onError.get()) {
101                 throw new Exception("onError handler should not be invoked on java.lang.Error.");
102             }
103             if (!closed.get()) {
104                 throw new Exception("Expected stream to be closed");
105             }
106         }
107     }
108 
testDefaultException()109     private static void testDefaultException() throws Exception {
110         TestException exception = new TestException();
111         AtomicBoolean closed = new AtomicBoolean();
112         AtomicInteger counter = new AtomicInteger();
113         try (RecordingStream r = new RecordingStream()) {
114             r.onEvent(e -> {
115                 if (counter.incrementAndGet() == 2) {
116                     r.close();
117                     return;
118                 }
119                 TestUtils.throwUnchecked(exception);
120             });
121             r.onClose(() -> {
122                 closed.set(true);
123             });
124             r.startAsync();
125             TestEvent e1 = new TestEvent();
126             e1.commit();
127             TestEvent e2 = new TestEvent();
128             e2.commit();
129             r.awaitTermination();
130             if (!exception.isPrinted()) {
131                 throw new Exception("Expected stack trace from Exception to be printed");
132             }
133             if (!closed.get()) {
134                 throw new Exception("Expected stream to be closed");
135             }
136         }
137     }
138 
testCustomException()139     private static void testCustomException() throws Exception {
140         TestException exception = new TestException();
141         AtomicBoolean closed = new AtomicBoolean();
142         AtomicBoolean received = new AtomicBoolean();
143         try (RecordingStream r = new RecordingStream()) {
144             r.onEvent(e -> {
145                 TestUtils.throwUnchecked(exception);
146             });
147             r.onError(t -> {
148                 received.set(t == exception);
149                 r.close();
150             });
151             r.onClose(() -> {
152                 closed.set(true);
153             });
154             r.startAsync();
155             TestEvent event = new TestEvent();
156             event.commit();
157             r.awaitTermination();
158             if (!received.get()) {
159                 throw new Exception("Did not receive expected exception in onError(...)");
160             }
161             if (exception.isPrinted()) {
162                 throw new Exception("Expected stack trace from Exception NOT to be printed");
163             }
164             if (!closed.get()) {
165                 throw new Exception("Expected stream to be closed");
166             }
167         }
168     }
169 
testOnFlushSanity()170     private static void testOnFlushSanity() throws Exception {
171         TestException exception = new TestException();
172         CountDownLatch received = new CountDownLatch(1);
173         try (RecordingStream r = new RecordingStream()) {
174             r.onFlush(() -> {
175                 TestUtils.throwUnchecked(exception);
176             });
177             r.onError(t -> {
178                 if (t == exception) {
179                     received.countDown();
180                 }
181             });
182             r.startAsync();
183             received.await();
184        }
185     }
186 
testOnCloseSanity()187     private static void testOnCloseSanity() throws Exception {
188         TestException exception = new TestException();
189         CountDownLatch received = new CountDownLatch(1);
190         try (RecordingStream r = new RecordingStream()) {
191             r.onFlush(() -> {
192                 r.close(); // will trigger onClose
193             });
194             r.onClose(() -> {
195                 TestUtils.throwUnchecked(exception); // will trigger onError
196             });
197             r.onError(t -> {
198                 if (t == exception) {
199                     received.countDown();
200                 }
201             });
202             r.startAsync();
203             received.await();
204         }
205     }
206 }
207