View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.mstat;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.apache.juneau.junit.bct.BctAssertions.*;
22  import static org.junit.jupiter.api.Assertions.*;
23  
24  import java.util.*;
25  
26  import org.apache.juneau.*;
27  import org.apache.juneau.cp.*;
28  import org.apache.juneau.rest.stats.*;
29  import org.junit.jupiter.api.*;
30  
31  class ThrownStore_Test extends TestBase {
32  
33  	//------------------------------------------------------------------------------------------------------------------
34  	// Basic tests
35  	//------------------------------------------------------------------------------------------------------------------
36  
37  	@Test void a01_testBasic() {
38  
39  		var t1 = new Throwable();
40  		t1.fillInStackTrace();
41  		var t2 = new Throwable();
42  		t2.fillInStackTrace();
43  
44  		var db = new ThrownStore();
45  
46  		assertEquals(1, db.add(t1).getCount());
47  		assertEquals(2, db.add(t1).getCount());
48  		assertEquals(1, db.add(t2).getCount());
49  
50  		assertEquals(db.getStats(t1).get().getHash(), db.getStats(t1).get().getHash());
51  		assertNotEquals(db.getStats(t2).get().getHash(), db.getStats(t1).get().getHash());
52  	}
53  
54  	@Test void a02_getStats() {
55  
56  		var t1 = new Throwable();
57  		t1.fillInStackTrace();
58  		var t2 = new Throwable();
59  		t2.fillInStackTrace();
60  
61  		var db = new ThrownStore();
62  
63  		db.add(t1);
64  		db.add(t1);
65  		db.add(t2);
66  
67  		List<ThrownStats> l = db.getStats();  // Should be a snapshot.
68  		db.add(t1);
69  
70  		assertSize(2, l);
71  		assertEquals(2, l.get(0).getCount());
72  		assertEquals(1, l.get(1).getCount());
73  	}
74  
75  	@Test void a03_reset() {
76  		var t1 = new Throwable();
77  		t1.fillInStackTrace();
78  
79  		var db = new ThrownStore();
80  		db.add(t1);
81  		db.reset();
82  
83  		assertEmpty(db.getStats(t1));
84  	}
85  
86  	@Test void a04_sameStackTraces() {
87  		var db = new ThrownStore();
88  
89  		var t1 = new Throwable() {
90  			@Override
91  			public StackTraceElement[] getStackTrace() {
92  				return a(
93  					new StackTraceElement("Foo", "bar", "Foo.class", 1),
94  					new StackTraceElement("Foo", "baz", "Foo.class", 2),
95  					new StackTraceElement("Stop", "baz", "Stop.class", 3),
96  					new StackTraceElement("Object", "baz", "Object.class", 6)
97  				);
98  			}
99  		};
100 		var t2 = new Throwable() {
101 			@Override
102 			public StackTraceElement[] getStackTrace() {
103 				return a(
104 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
105 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
106 					new StackTraceElement("Stop", "baz", "Stop.class", 3),
107 					new StackTraceElement("Object", "baz", "Object.class", 6)
108 				);
109 			}
110 		};
111 
112 		db.add(t1);
113 		db.add(t2);
114 
115 		assertEquals(2, db.getStats(t1).get().getCount());
116 		assertEquals(2, db.getStats(t2).get().getCount());
117 	}
118 
119 	@Test void a05_slightlyDifferentStackTraces() {
120 		var db = new ThrownStore();
121 
122 		var t1 = new Throwable() {
123 			@Override
124 			public StackTraceElement[] getStackTrace() {
125 				return a(
126 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
127 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
128 					new StackTraceElement("Stop", "baz", "Stop.class", 3),
129 					new StackTraceElement("Object", "baz", "Object.class", 6)
130 				);
131 			}
132 		};
133 		var t2 = new Throwable() {
134 			@Override
135 			public StackTraceElement[] getStackTrace() {
136 				return a(
137 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
138 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
139 					new StackTraceElement("Stop", "baz", "Stop.class", 3),
140 					new StackTraceElement("Object", "baz", "Object.class", 7)
141 				);
142 			}
143 		};
144 
145 		db.add(t1);
146 		db.add(t2);
147 
148 		assertEquals(1, db.getStats(t1).get().getCount());
149 		assertEquals(1, db.getStats(t2).get().getCount());
150 	}
151 
152 	@Test void a06_proxyElements() {
153 		var db = new ThrownStore();
154 
155 		var t1 = new Throwable() {
156 			@Override
157 			public StackTraceElement[] getStackTrace() {
158 				return a(
159 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
160 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
161 					new StackTraceElement("Stop$1", "baz", "Stop.class", 6),
162 					new StackTraceElement("Object", "baz", "Object.class", 6)
163 				);
164 			}
165 		};
166 		var t2 = new Throwable() {
167 			@Override
168 			public StackTraceElement[] getStackTrace() {
169 				return a(
170 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
171 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
172 					new StackTraceElement("Stop$2", "baz", "Stop.class", 6),
173 					new StackTraceElement("Object", "baz", "Object.class", 6)
174 				);
175 			}
176 		};
177 
178 		db.add(t1);
179 		db.add(t2);
180 
181 		assertEquals(2, db.getStats(t1).get().getCount());
182 		assertEquals(2, db.getStats(t2).get().getCount());
183 	}
184 
185 	//------------------------------------------------------------------------------------------------------------------
186 	// Builder tests.
187 	//------------------------------------------------------------------------------------------------------------------
188 
189 	@Test void b01_builder_default() {
190 		assertInstanceOf(ThrownStore.class, ThrownStore.create().build());
191 	}
192 
193 	public static class B1 extends ThrownStore{}
194 
195 	@Test void b02_builder_implClass() {
196 		assertInstanceOf(B1.class, ThrownStore.create().type(B1.class).build());
197 	}
198 
199 	public static class B4 extends ThrownStore {
200 		public B4(ThrownStore.Builder b) throws Exception {
201 			throw new RuntimeException("foobar");
202 		}
203 	}
204 
205 	@Test void b04_builder_implClass_bad() {
206 		assertThrowsWithMessage(Exception.class, "foobar", ()->ThrownStore.create().type(B4.class).build());
207 	}
208 
209 	public static class B5a {}
210 
211 	public static class B5b extends ThrownStore {
212 		public B5b(ThrownStore.Builder b, B5a x) throws Exception {
213 			if (x == null)
214 				throw new RuntimeException("Bad");
215 		}
216 	}
217 
218 	public static class B5c extends ThrownStore {
219 		public B5c(ThrownStore.Builder b, Optional<B5a> x) throws Exception {
220 			if (x == null)
221 				throw new RuntimeException("Bad");
222 		}
223 	}
224 
225 	@Test void b05_builder_beanFactory() {
226 		var bs = BeanStore.create().build();
227 
228 		assertThrowsWithMessage(Exception.class, "Public constructor found but could not find prerequisites: B5a", ()->ThrownStore.create(bs).type(B5b.class).build());
229 		assertInstanceOf(B5c.class, ThrownStore.create(bs).type(B5c.class).build());
230 
231 		bs.addBean(B5a.class, new B5a());
232 		assertInstanceOf(B5b.class, ThrownStore.create(bs).type(B5b.class).build());
233 		assertInstanceOf(B5c.class, ThrownStore.create(bs).type(B5c.class).build());
234 	}
235 
236 	public static class B6a {}
237 
238 	public static class B6b extends ThrownStats {
239 		public B6b(ThrownStats.Builder b, B6a x) throws Exception {
240 			super(b);
241 			if (x == null)
242 				throw new RuntimeException("Bad");
243 		}
244 	}
245 
246 	public static class B6c extends ThrownStats {
247 		public B6c(ThrownStats.Builder b, Optional<B6a> x) throws Exception {
248 			super(b);
249 			if (x == null)
250 				throw new RuntimeException("Bad");
251 		}
252 	}
253 
254 	@Test void b06_statsImplClass() {
255 		var bs = BeanStore.create().build();
256 
257 		var t1 = new Throwable();
258 		t1.fillInStackTrace();
259 
260 		assertThrowsWithMessage(Exception.class, "Public constructor found but could not find prerequisites: B6a", ()->ThrownStore.create(bs).statsImplClass(B6b.class).build().add(t1));
261 		assertInstanceOf(B6c.class, ThrownStore.create(bs).statsImplClass(B6c.class).build().add(t1));
262 
263 		bs.addBean(B6a.class, new B6a());
264 		assertInstanceOf(B6b.class, ThrownStore.create(bs).statsImplClass(B6b.class).build().add(t1));
265 		assertInstanceOf(B6c.class, ThrownStore.create(bs).statsImplClass(B6c.class).build().add(t1));
266 	}
267 
268 	//------------------------------------------------------------------------------------------------------------------
269 	// ThrownStats tests.
270 	//------------------------------------------------------------------------------------------------------------------
271 
272 	@Test void c01_thrownStats_basic() {
273 		var t1 = new Throwable("foo");
274 		t1.fillInStackTrace();
275 		var t2 = new Throwable("bar", t1);
276 		t2.fillInStackTrace();
277 
278 		var store = ThrownStore.create().build();
279 
280 		var stats = store.add(t2);
281 		assertNotEquals(0L, stats.getHash());
282 		assertNotEquals(0L, stats.getGuid());
283 		assertNotEquals(0L, stats.getFirstOccurrence());
284 		assertNotEquals(0L, stats.getLastOccurrence());
285 		assertEquals("bar", stats.getFirstMessage());
286 		assertContains("org.apache.juneau", r(stats.getStackTrace()));
287 		assertContains("bar", stats);
288 
289 		stats = stats.clone();
290 		assertNotEquals(0L, stats.getHash());
291 		assertNotEquals(0L, stats.getGuid());
292 		assertNotEquals(0L, stats.getFirstOccurrence());
293 		assertNotEquals(0L, stats.getLastOccurrence());
294 		assertEquals("bar", stats.getFirstMessage());
295 		assertContains("org.apache.juneau", r(stats.getStackTrace()));
296 		assertContains("bar", stats);
297 
298 		stats = stats.getCausedBy().get();
299 		assertNotEquals(0L, stats.getHash());
300 		assertNotEquals(0L, stats.getGuid());
301 		assertNotEquals(0L, stats.getFirstOccurrence());
302 		assertNotEquals(0L, stats.getLastOccurrence());
303 		assertEquals("foo", stats.getFirstMessage());
304 		assertContains("org.apache.juneau", r(stats.getStackTrace()));
305 		assertContains("foo", stats);
306 	}
307 
308 	//------------------------------------------------------------------------------------------------------------------
309 	// ThrownStore tests.
310 	//------------------------------------------------------------------------------------------------------------------
311 
312 	public static class D1 {}
313 	public static class D2 {}
314 
315 	@Test void d01_ignoreClasses() {
316 		var db = ThrownStore.create().ignoreClasses(D1.class,D2.class,ThrownStore_Test.class).build();
317 
318 		var t1 = new Throwable() {
319 			@Override
320 			public StackTraceElement[] getStackTrace() {
321 				return a(
322 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
323 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
324 					new StackTraceElement(D1.class.getName(), "baz", "D1.class", 3),
325 					new StackTraceElement(D1.class.getName()+"$X", "baz", "D1.X.class", 4),
326 					new StackTraceElement("Object", "baz", "Object.class", 5)
327 				);
328 			}
329 		};
330 		var t2 = new Throwable() {
331 			@Override
332 			public StackTraceElement[] getStackTrace() {
333 				return a(
334 					new StackTraceElement("Foo", "bar", "Foo.class", 1),
335 					new StackTraceElement("Foo", "baz", "Foo.class", 2),
336 					new StackTraceElement(D2.class.getName(), "baz", "D2.class", 3),
337 					new StackTraceElement(D2.class.getName()+"$X", "baz", "D2.X.class", 4),
338 					new StackTraceElement("Object", "baz", "Object.class", 5)
339 				);
340 			}
341 		};
342 
343 		db.add(t1);
344 		db.add(t2);
345 
346 		assertList(db.getStats(t1).get().getStackTrace(), "Foo.bar(Foo.class:1)", "Foo.baz(Foo.class:2)", "<ignored>", "<ignored>", "Object.baz(Object.class:5)");
347 		assertList(db.getStats(t2).get().getStackTrace(), "Foo.bar(Foo.class:1)", "Foo.baz(Foo.class:2)", "<ignored>", "<ignored>", "Object.baz(Object.class:5)");
348 
349 		assertEquals(2, db.getStats(t1).get().getCount());
350 		assertEquals(2, db.getStats(t2).get().getCount());
351 
352 		var db2 = ThrownStore.create().parent(db).build();
353 
354 		db2.add(t1);
355 		db2.add(t2);
356 
357 		assertList(db2.getStats(t1).get().getStackTrace(), "Foo.bar(Foo.class:1)", "Foo.baz(Foo.class:2)", "<ignored>", "<ignored>", "Object.baz(Object.class:5)");
358 		assertList(db2.getStats(t2).get().getStackTrace(), "Foo.bar(Foo.class:1)", "Foo.baz(Foo.class:2)", "<ignored>", "<ignored>", "Object.baz(Object.class:5)");
359 
360 		assertEquals(2, db2.getStats(t1).get().getCount());
361 		assertEquals(2, db2.getStats(t2).get().getCount());
362 		assertEquals(4, db.getStats(t1).get().getCount());
363 		assertEquals(4, db.getStats(t2).get().getCount());
364 	}
365 }