1 /*
2  * Copyright (c) 2014, 2016, 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  * @summary close handlers and closing streams
27  * @bug 8044047 8147505
28  */
29 
30 package org.openjdk.tests.java.util.stream;
31 
32 import java.util.Arrays;
33 import java.util.stream.OpTestCase;
34 import java.util.stream.Stream;
35 
36 import org.testng.annotations.Test;
37 
38 import static java.util.stream.LambdaTestHelpers.countTo;
39 import static java.util.stream.ThrowableHelper.checkNPE;
40 import static java.util.stream.ThrowableHelper.checkISE;
41 
42 @Test(groups = { "serialization-hostile" })
43 public class StreamCloseTest extends OpTestCase {
testNullCloseHandler()44     public void testNullCloseHandler() {
45         checkNPE(() -> Stream.of(1).onClose(null));
46     }
47 
testEmptyCloseHandler()48     public void testEmptyCloseHandler() {
49         try (Stream<Integer> ints = countTo(100).stream()) {
50             ints.forEach(i -> {});
51         }
52     }
53 
testOneCloseHandler()54     public void testOneCloseHandler() {
55         final boolean[] holder = new boolean[1];
56         Runnable closer = () -> { holder[0] = true; };
57 
58         try (Stream<Integer> ints = countTo(100).stream()) {
59             ints.onClose(closer);
60             ints.forEach(i -> {});
61         }
62         assertTrue(holder[0]);
63 
64         Arrays.fill(holder, false);
65         try (Stream<Integer> ints = countTo(100).stream().onClose(closer)) {
66             ints.forEach(i -> {});
67         }
68         assertTrue(holder[0]);
69 
70         Arrays.fill(holder, false);
71         try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer)) {
72             ints.forEach(i -> {});
73         }
74         assertTrue(holder[0]);
75 
76         Arrays.fill(holder, false);
77         try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer).filter(e -> true)) {
78             ints.forEach(i -> {});
79         }
80         assertTrue(holder[0]);
81     }
82 
testTwoCloseHandlers()83     public void testTwoCloseHandlers() {
84         final boolean[] holder = new boolean[2];
85         Runnable close1 = () -> { holder[0] = true; };
86         Runnable close2 = () -> { holder[1] = true; };
87 
88         try (Stream<Integer> ints = countTo(100).stream()) {
89             ints.onClose(close1).onClose(close2);
90             ints.forEach(i -> {});
91         }
92         assertTrue(holder[0] && holder[1]);
93 
94         Arrays.fill(holder, false);
95         try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2)) {
96             ints.forEach(i -> {});
97         }
98         assertTrue(holder[0] && holder[1]);
99 
100         Arrays.fill(holder, false);
101         try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2)) {
102             ints.forEach(i -> {});
103         }
104         assertTrue(holder[0] && holder[1]);
105 
106         Arrays.fill(holder, false);
107         try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true)) {
108             ints.forEach(i -> {});
109         }
110         assertTrue(holder[0] && holder[1]);
111     }
112 
testCascadedExceptions()113     public void testCascadedExceptions() {
114         final boolean[] holder = new boolean[3];
115         boolean caught = false;
116         Runnable close1 = () -> { holder[0] = true; throw new RuntimeException("1"); };
117         Runnable close2 = () -> { holder[1] = true; throw new RuntimeException("2"); };
118         Runnable close3 = () -> { holder[2] = true; throw new RuntimeException("3"); };
119 
120         try (Stream<Integer> ints = countTo(100).stream()) {
121             ints.onClose(close1).onClose(close2).onClose(close3);
122             ints.forEach(i -> {});
123         }
124         catch (RuntimeException e) {
125             assertCascaded(e, 3);
126             assertTrue(holder[0] && holder[1] && holder[2]);
127             caught = true;
128         }
129         assertTrue(caught);
130 
131         Arrays.fill(holder, false);
132         caught = false;
133         try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2).onClose(close3)) {
134             ints.forEach(i -> {});
135         }
136         catch (RuntimeException e) {
137             assertCascaded(e, 3);
138             assertTrue(holder[0] && holder[1] && holder[2]);
139             caught = true;
140         }
141         assertTrue(caught);
142 
143         caught = false;
144         Arrays.fill(holder, false);
145         try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).onClose(close3)) {
146             ints.forEach(i -> {});
147         }
148         catch (RuntimeException e) {
149             assertCascaded(e, 3);
150             assertTrue(holder[0] && holder[1] && holder[2]);
151             caught = true;
152         }
153         assertTrue(caught);
154 
155         caught = false;
156         Arrays.fill(holder, false);
157         try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true).onClose(close3)) {
158             ints.forEach(i -> {});
159         }
160         catch (RuntimeException e) {
161             assertCascaded(e, 3);
162             assertTrue(holder[0] && holder[1] && holder[2]);
163             caught = true;
164         }
165         assertTrue(caught);
166     }
167 
assertCascaded(RuntimeException e, int n)168     private void assertCascaded(RuntimeException e, int n) {
169         assertTrue(e.getMessage().equals("1"));
170         assertTrue(e.getSuppressed().length == n - 1);
171         for (int i=0; i<n-1; i++)
172         assertTrue(e.getSuppressed()[i].getMessage().equals(String.valueOf(i + 2)));
173     }
174 
testConsumed()175     public void testConsumed() {
176         try(Stream<Integer> s = countTo(100).stream()) {
177             s.forEach(i -> {});
178             // Adding onClose handler when stream is consumed is illegal
179             // handler must not be registered
180             checkISE(() -> s.onClose(() -> fail("1")));
181         }
182 
183         // close() must be idempotent:
184         // second close() invoked at the end of try-with-resources must have no effect
185         try(Stream<Integer> s = countTo(100).stream()) {
186             s.close();
187             // Adding onClose handler when stream is closed is also illegal
188             checkISE(() -> s.onClose(() -> fail("3")));
189         }
190     }
191 }
192