1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core;
15
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertTrue;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.channels.FileChannel;
22
23 import org.junit.Before;
24 import org.junit.Ignore;
25 import org.junit.Test;
26
27 import ch.qos.logback.core.contention.RunnableWithCounterAndDone;
28 import ch.qos.logback.core.encoder.EchoEncoder;
29 import ch.qos.logback.core.recovery.RecoveryCoordinator;
30 import ch.qos.logback.core.recovery.RecoveryListener;
31 import ch.qos.logback.core.recovery.ResilientFileOutputStream;
32 import ch.qos.logback.core.status.OnConsoleStatusListener;
33 import ch.qos.logback.core.testUtil.CoreTestConstants;
34 import ch.qos.logback.core.testUtil.RandomUtil;
35 import ch.qos.logback.core.util.ResilienceUtil;
36
37 public class FileAppenderResilienceTest implements RecoveryListener {
38
39 FileAppender<Object> fa = new FileAppender<Object>();
40
41 ResilientFileOutputStream resilientFOS;
42
43 Context context = new ContextBase();
44 int diff = RandomUtil.getPositiveInt();
45 String outputDirStr = CoreTestConstants.OUTPUT_DIR_PREFIX + "resilience-" + diff + "/";
46
47
48
49 String logfileStr = outputDirStr + "output.log";
50
51 boolean failedState = false;
52
53 int recoveryCounter = 0;
54 int failureCounter = 0;
55
56
57 @Before
58 public void setUp() throws InterruptedException {
59
60 context.getStatusManager().add(new OnConsoleStatusListener());
61
62 File outputDir = new File(outputDirStr);
63 outputDir.mkdirs();
64
65 fa.setContext(context);
66 fa.setName("FILE");
67 fa.setEncoder(new EchoEncoder<Object>());
68 fa.setFile(logfileStr);
69 fa.start();
70 resilientFOS = (ResilientFileOutputStream) fa.getOutputStream();
71 resilientFOS.addRecoveryListener(this);
72
73 }
74
75 @Test
76 @Ignore
77 public void manual() throws InterruptedException, IOException {
78 Runner runner = new Runner(fa);
79 Thread t = new Thread(runner);
80 t.start();
81
82 while (true) {
83 Thread.sleep(110);
84 }
85 }
86
87 @Test
88 public void smoke() throws InterruptedException, IOException {
89 Runner runner = new Runner(fa);
90 Thread t = new Thread(runner);
91 t.start();
92
93 double delayCoefficient = 2.0;
94 for (int i = 0; i < 5; i++) {
95 Thread.sleep((int) (RecoveryCoordinator.BACKOFF_COEFFICIENT_MIN * delayCoefficient));
96 closeLogFileOnPurpose();
97 }
98 runner.setDone(true);
99 t.join();
100
101 double bestCaseSuccessRatio = 1 / delayCoefficient;
102
103 double lossinessFactor = 0.35;
104 double resilianceFactor = (1 - lossinessFactor);
105
106 assertTrue("at least one recovery should have occured", recoveryCounter > 0);
107 assertTrue("at least one failure should have occured", failureCounter > 0);
108
109 System.out.println("recoveryCounter=" + recoveryCounter);
110 System.out.println("failureCounter=" + failureCounter);
111
112
113
114 String errmsg0 = "failureCounter="+failureCounter+" must be greater or equal to recoveryCounter="+recoveryCounter;
115 assertTrue(errmsg0, failureCounter >= recoveryCounter);
116
117 String errmsg1 = "Difference between failureCounter="+failureCounter+" and recoveryCounter="+recoveryCounter+" should not exceeed 1";
118 assertTrue(errmsg1, failureCounter - recoveryCounter <= 1);
119
120
121
122 int actuallyWritten = ResilienceUtil.countLines(logfileStr, "^hello (\\d{1,5})$");
123 long exptectedWrites = runner.getCounter()-recoveryCounter;
124 assertEquals(exptectedWrites, actuallyWritten);
125 }
126
127 private void closeLogFileOnPurpose() throws IOException {
128 ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) fa.getOutputStream();
129 FileChannel fileChannel = resilientFOS.getChannel();
130 fileChannel.close();
131 }
132
133 @Override
134 public void newFailure(IOException e) {
135 failedState = true;
136 failureCounter++;
137
138 }
139
140 @Override
141 public void recoveryOccured() {
142 failedState = false;
143 recoveryCounter++;
144 }
145
146 class Runner extends RunnableWithCounterAndDone {
147 FileAppender<Object> fa;
148
149 Runner(FileAppender<Object> fa) {
150 this.fa = fa;
151 }
152
153 public void run() {
154 while (!isDone()) {
155 fa.doAppend("hello " + counter);
156 if(!FileAppenderResilienceTest.this.failedState) {
157 counter++;
158 }
159 if (counter % 128 == 0) {
160 try {
161 Thread.sleep(10);
162 } catch (InterruptedException e) {
163 }
164 }
165 }
166 }
167
168 }
169 }
170