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