1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.net;
15  
16  import static org.mockito.ArgumentMatchers.anyInt;
17  import static org.mockito.Mockito.mock;
18  import static org.mockito.Mockito.spy;
19  import static org.mockito.Mockito.timeout;
20  import static org.mockito.Mockito.verify;
21  import static org.mockito.Mockito.when;
22  
23  import java.io.IOException;
24  import java.io.ObjectInputStream;
25  import java.io.OutputStream;
26  import java.io.Serializable;
27  import java.net.ServerSocket;
28  import java.net.Socket;
29  import java.util.concurrent.LinkedBlockingDeque;
30  import java.util.concurrent.ScheduledExecutorService;
31  import java.util.concurrent.ThreadPoolExecutor;
32  import java.util.concurrent.TimeUnit;
33  
34  import org.junit.jupiter.api.AfterEach;
35  import org.junit.jupiter.api.Assertions;
36  import org.junit.jupiter.api.BeforeEach;
37  import org.junit.jupiter.api.Disabled;
38  import org.junit.jupiter.api.Test;
39  
40  import ch.qos.logback.core.net.mock.MockContext;
41  import ch.qos.logback.core.net.server.test.ServerSocketUtil;
42  import ch.qos.logback.core.spi.PreSerializationTransformer;
43  import ch.qos.logback.core.util.ExecutorServiceUtil;
44  
45  /**
46   * Integration tests for {@link ch.qos.logback.core.net.AbstractSocketAppender}.
47   *
48   * @author Carl Harris
49   * @author Sebastian Gröbler
50   */
51  public class AbstractSocketAppenderIntegrationTest {
52  
53      private static final int TIMEOUT = 2000;
54  
55      private ThreadPoolExecutor threadPoolExecutor = ExecutorServiceUtil.newThreadPoolExecutor();
56      private MockContext mockContext = new MockContext(threadPoolExecutor);
57      private AutoFlushingObjectWriter objectWriter;
58      private ObjectWriterFactory objectWriterFactory = new SpyProducingObjectWriterFactory();
59      private LinkedBlockingDeque<String> deque = spy(new LinkedBlockingDeque<String>(1));
60      private QueueFactory queueFactory = mock(QueueFactory.class);
61      private InstrumentedSocketAppender instrumentedAppender = new InstrumentedSocketAppender(queueFactory,
62              objectWriterFactory);
63  
64      @BeforeEach
65      public void setUp() throws Exception {
66          when(queueFactory.<String>newLinkedBlockingDeque(anyInt())).thenReturn(deque);
67          instrumentedAppender.setContext(mockContext);
68      }
69  
70      @AfterEach
71      public void tearDown() throws Exception {
72          instrumentedAppender.stop();
73          Assertions.assertFalse(instrumentedAppender.isStarted());
74          threadPoolExecutor.shutdownNow();
75          Assertions.assertTrue(threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.MILLISECONDS));
76      }
77  
78      @Disabled // JDK 16
79      @Test
80      public void dispatchesEvents() throws Exception {
81  
82          // given
83          ServerSocket serverSocket = ServerSocketUtil.createServerSocket();
84          instrumentedAppender.setRemoteHost(serverSocket.getInetAddress().getHostAddress());
85          instrumentedAppender.setPort(serverSocket.getLocalPort());
86          instrumentedAppender.start();
87  
88          Socket appenderSocket = serverSocket.accept();
89          serverSocket.close();
90  
91          // when
92          instrumentedAppender.append("some event");
93  
94          // wait for event to be taken from deque and being written into the stream
95          verify(deque, timeout(TIMEOUT).atLeastOnce()).takeFirst();
96          verify(objectWriter, timeout(TIMEOUT)).write("some event");
97  
98          // then
99          ObjectInputStream ois = new ObjectInputStream(appenderSocket.getInputStream());
100         Assertions.assertEquals( ois.readObject(), "some event");
101         appenderSocket.close();
102     }
103 
104     private static class InstrumentedSocketAppender extends AbstractSocketAppender<String> {
105 
106         public InstrumentedSocketAppender(QueueFactory queueFactory, ObjectWriterFactory objectWriterFactory) {
107             super(queueFactory, objectWriterFactory);
108         }
109 
110         @Override
111         protected void postProcessEvent(String event) {
112         }
113 
114         @Override
115         protected PreSerializationTransformer<String> getPST() {
116             return new PreSerializationTransformer<String>() {
117                 public Serializable transform(String event) {
118                     return event;
119                 }
120             };
121         }
122     }
123 
124     private class SpyProducingObjectWriterFactory extends ObjectWriterFactory {
125 
126         @Override
127         public AutoFlushingObjectWriter newAutoFlushingObjectWriter(OutputStream outputStream) throws IOException {
128             objectWriter = spy(super.newAutoFlushingObjectWriter(outputStream));
129             return objectWriter;
130         }
131     }
132 }