deja vu javazone 2013
DESCRIPTION
Bugs in production systems are typically communicated in stack traces. But why don't we communicate in unit tests? This presentation discuss a concrete open source Java framework that allows production systems to communicate bugs as test cases. It will produce deterministic, sand-boxable test cases having identical execution paths as the original run. Using the framework correctly will even make multi-threaded scenarios re-playable.TRANSCRIPT
Replay your productions bugsJavaZone 2013
Mads Enevoldsen, Developer, Jayway
Overview
• Problem Definition
• Tracing
• Reproducablilty
• Threads
• Example Architecture
Part I
Problem Definition
Spot of bother
• Why are errors communicated in stack traces?
• Why are production bugs hunted down by inspecting log files?
• Why can’t we communicate in running code?
Unit test
• Proves how code works
• Deterministic
• Environment agnostic
Execution path
1 public class Example {
2
3 public void foo() {
4 bar();
5 // exception occurs
6 }
7
8 private void bar() {
9 //...
10 }
11 }
Computable?
• Reasoning about code
• Source code vs. running code
Part II
Tracing
Deja Vu
• Open source
• Define trace points in your code
• Serialize traces to unit tests
Example
1 public class Example {
2
3 @Traced
4 public void foo() {
5 bar();
6 //...
7 }
8
9 private void bar() {
10 //...
11 }
12 }
@Traced
• Method annotation
• Define ”lumps” of code to be traced
• Store arguments and method ”pointer”
• No state in objects
Setup
• Install callback
• Trace-mode for tracing @Traced
• Replay-mode for re-running generated traces
Replay
1 public class ExampleTest{
2
3 @Test
4 public void exampletest() throws Throwable {
5 TraceBuilder builder = TraceBuilder.build().
6 setMethod(Example.class);
7
8 builder.run();
9 }
10 }
Part III
Reproducability
@Impure
• Randomized/Non-deterministic
• Environment dependent
• Threading
Rules of the game
• Immutable
• Must be serializable++
Lucky number bug
1 public class AlmostWorking {
2
3 @Traced
4 public void getLucky() {
5 Long value = timeStamp();
6 Long luckyNumber = 2304432 / ( value % 1001 );
7 System.out.println( "My lucky number is: "+luckyNumber);
8 }
9
10 @Impure
11 private Long timeStamp() {
12 return System.nanoTime();
13 }
14 }
Overhead
• Execution overhead in intercepting calls
• Memory overhead in storing ”impure” values
• Immutable overhead
Part IV
Threads
Threads
• Non-deterministic!
• For pure parts it doesn’t matter
@AttachThread
• Includes a thread in a trace
• Trace is not done until trace method is executed...
• ...and all attached threads are done executing
• Impure parts are replayed in same order
Example
1 public class WithThreads {
2
3 private ExecutorService executorService;
4
5 public void initialize() {
6 executorService = Executors.newCachedThreadPool();
7 }
8
9 @Traced
10 public void begin( Integer threads) {
11 initialize();
12 for ( int i=0; i<threads; i++ ) {
13 runInThreadPool(new Runner());
14 }
15 }
16
17 @AttachThread
18 private void runInThreadPool( Runnable runnable ) {
19 executorService.submit(runnable);
20 }
21 }
Part V
Example Architecture
Usecases
• Trace on each ’usecase’
• Usecase becomes a programming concept
Thank you
• https://github.com/madsenevoldsen/dejavu
• http://www.jayway.com/2013/01/09/deja-vu/