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