View Javadoc
1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, 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 v2.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.ThreadPoolExecutor;
31  import java.util.concurrent.TimeUnit;
32  
33  import org.junit.jupiter.api.AfterEach;
34  import org.junit.jupiter.api.Assertions;
35  import org.junit.jupiter.api.BeforeEach;
36  import org.junit.jupiter.api.Disabled;
37  import org.junit.jupiter.api.Test;
38  
39  import ch.qos.logback.core.net.mock.MockContext;
40  import ch.qos.logback.core.spi.PreSerializationTransformer;
41  import ch.qos.logback.core.util.ExecutorServiceUtil;
42  
43  /**
44   * Integration tests for {@link ch.qos.logback.core.net.AbstractSocketAppender}.
45   *
46   * @author Carl Harris
47   * @author Sebastian Gröbler
48   */
49  public class AbstractSocketAppenderIntegrationTest {
50  
51      private static final int TIMEOUT = 2000;
52  
53      private ThreadPoolExecutor threadPoolExecutor = ExecutorServiceUtil.newThreadPoolExecutor();
54      private MockContext mockContext = new MockContext(threadPoolExecutor);
55      private AutoFlushingObjectWriter objectWriter;
56      private ObjectWriterFactory objectWriterFactory = new SpyProducingObjectWriterFactory();
57      private LinkedBlockingDeque<String> deque = spy(new LinkedBlockingDeque<String>(1));
58      private QueueFactory queueFactory = mock(QueueFactory.class);
59      private InstrumentedSocketAppender instrumentedAppender = new InstrumentedSocketAppender(queueFactory,
60              objectWriterFactory);
61  
62      @BeforeEach
63      public void setUp() throws Exception {
64          when(queueFactory.<String>newLinkedBlockingDeque(anyInt())).thenReturn(deque);
65          instrumentedAppender.setContext(mockContext);
66      }
67  
68      @AfterEach
69      public void tearDown() throws Exception {
70          instrumentedAppender.stop();
71          Assertions.assertFalse(instrumentedAppender.isStarted());
72          threadPoolExecutor.shutdownNow();
73          Assertions.assertTrue(threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.MILLISECONDS));
74      }
75  
76      @Disabled // JDK 16
77      @Test
78      public void dispatchesEvents() throws Exception {
79  
80          // given
81          ServerSocket serverSocket = ServerSocketUtil.createServerSocket();
82          instrumentedAppender.setRemoteHost(serverSocket.getInetAddress().getHostAddress());
83          instrumentedAppender.setPort(serverSocket.getLocalPort());
84          instrumentedAppender.start();
85  
86          Socket appenderSocket = serverSocket.accept();
87          serverSocket.close();
88  
89          // when
90          instrumentedAppender.append("some event");
91  
92          // wait for event to be taken from deque and being written into the stream
93          verify(deque, timeout(TIMEOUT).atLeastOnce()).takeFirst();
94          verify(objectWriter, timeout(TIMEOUT)).write("some event");
95  
96          // then
97          ObjectInputStream ois = new ObjectInputStream(appenderSocket.getInputStream());
98          Assertions.assertEquals( ois.readObject(), "some event");
99          appenderSocket.close();
100     }
101 
102     private static class InstrumentedSocketAppender extends AbstractSocketAppender<String> {
103 
104         public InstrumentedSocketAppender(QueueFactory queueFactory, ObjectWriterFactory objectWriterFactory) {
105             super(queueFactory, objectWriterFactory);
106         }
107 
108         @Override
109         protected void postProcessEvent(String event) {
110         }
111 
112         @Override
113         protected PreSerializationTransformer<String> getPST() {
114             return new PreSerializationTransformer<String>() {
115                 public Serializable transform(String event) {
116                     return event;
117                 }
118             };
119         }
120     }
121 
122     private class SpyProducingObjectWriterFactory extends ObjectWriterFactory {
123 
124         @Override
125         public AutoFlushingObjectWriter newAutoFlushingObjectWriter(OutputStream outputStream) throws IOException {
126             objectWriter = spy(super.newAutoFlushingObjectWriter(outputStream));
127             return objectWriter;
128         }
129     }
130 }