1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.agent.rt.internal.output; 13 14 import static org.junit.Assert.assertEquals; 15 import static org.junit.Assert.assertFalse; 16 import static org.junit.Assert.assertTrue; 17 18 import java.io.IOException; 19 import java.io.OutputStream; 20 import java.util.List; 21 import java.util.concurrent.Callable; 22 import java.util.concurrent.Future; 23 24 import org.jacoco.core.data.ExecutionDataStore; 25 import org.jacoco.core.data.ExecutionDataWriter; 26 import org.jacoco.core.data.SessionInfo; 27 import org.jacoco.core.data.SessionInfoStore; 28 import org.jacoco.core.runtime.RemoteControlReader; 29 import org.jacoco.core.runtime.RemoteControlWriter; 30 import org.jacoco.core.runtime.RuntimeData; 31 import org.junit.Before; 32 import org.junit.Test; 33 34 /** 35 * Unit tests for {@link TcpConnection}. 36 */ 37 public class TcpConnectionTest extends ExecutorTestBase { 38 39 private MockSocketConnection mockConnection; 40 41 private RuntimeData data; 42 43 @Before 44 @Override 45 public void setup() throws Exception { 46 super.setup(); 47 mockConnection = new MockSocketConnection(); 48 data = new RuntimeData(); 49 } 50 51 @Test(expected = IOException.class) 52 public void testInvalidHeader() throws Exception { 53 final OutputStream remoteOut = mockConnection.getSocketB() 54 .getOutputStream(); 55 remoteOut.write(0x01); 56 remoteOut.write(0xC0); 57 remoteOut.write(0xCA); 58 final TcpConnection connection = new TcpConnection( 59 mockConnection.getSocketA(), data); 60 connection.init(); 61 connection.run(); 62 } 63 64 @Test(expected = IOException.class) 65 public void testInvalidContent() throws Exception { 66 final OutputStream remoteOut = mockConnection.getSocketB() 67 .getOutputStream(); 68 new ExecutionDataWriter(remoteOut); 69 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 70 data); 71 con.init(); 72 remoteOut.write(123); 73 con.run(); 74 } 75 76 /** 77 * Remote endpoint is closed after a valid header has been send. 78 */ 79 @Test 80 public void testRemoteClose() throws Exception { 81 final OutputStream remoteOut = mockConnection.getSocketB() 82 .getOutputStream(); 83 new ExecutionDataWriter(remoteOut); 84 85 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 86 data); 87 con.init(); 88 89 final Future<Void> f = executor.submit(new Callable<Void>() { 90 public Void call() throws Exception { 91 con.run(); 92 return null; 93 } 94 }); 95 96 assertBlocks(f); 97 98 mockConnection.getSocketA().waitUntilInputBufferIsEmpty(); 99 mockConnection.getSocketB().close(); 100 f.get(); 101 } 102 103 /** 104 * Local socket is closed while waiting for commands. 105 * 106 * @throws Exception 107 */ 108 @Test 109 public void testLocalClose() throws Exception { 110 final OutputStream remoteOut = mockConnection.getSocketB() 111 .getOutputStream(); 112 new ExecutionDataWriter(remoteOut); 113 114 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 115 data); 116 con.init(); 117 118 final Future<Void> f = executor.submit(new Callable<Void>() { 119 public Void call() throws Exception { 120 con.run(); 121 return null; 122 } 123 }); 124 125 assertBlocks(f); 126 127 con.close(); 128 f.get(); 129 } 130 131 @Test 132 public void testRemoteDump() throws Exception { 133 data.getExecutionData(Long.valueOf(0x12345678), "Foo", 42) 134 .getProbes()[0] = true; 135 data.setSessionId("stubid"); 136 137 final RemoteControlWriter remoteWriter = new RemoteControlWriter( 138 mockConnection.getSocketB().getOutputStream()); 139 140 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 141 data); 142 con.init(); 143 144 final Future<Void> f = executor.submit(new Callable<Void>() { 145 public Void call() throws Exception { 146 con.run(); 147 return null; 148 } 149 }); 150 151 assertBlocks(f); 152 153 remoteWriter.visitDumpCommand(true, false); 154 readAndAssertData(); 155 156 con.close(); 157 f.get(); 158 } 159 160 @Test 161 public void testLocalDump() throws Exception { 162 data.getExecutionData(Long.valueOf(0x12345678), "Foo", 42) 163 .getProbes()[0] = true; 164 data.setSessionId("stubid"); 165 166 new RemoteControlWriter(mockConnection.getSocketB().getOutputStream()); 167 168 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 169 data); 170 con.init(); 171 172 final Future<Void> f = executor.submit(new Callable<Void>() { 173 public Void call() throws Exception { 174 con.run(); 175 return null; 176 } 177 }); 178 179 assertBlocks(f); 180 181 con.writeExecutionData(false); 182 readAndAssertData(); 183 184 con.close(); 185 f.get(); 186 } 187 188 @Test 189 public void testLocalDumpWithoutInit() throws Exception { 190 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 191 data); 192 // Must not write any data as we're not initialized: 193 con.writeExecutionData(false); 194 195 assertEquals(0, 196 mockConnection.getSocketB().getInputStream().available()); 197 } 198 199 private void readAndAssertData() throws IOException { 200 final RemoteControlReader remoteReader = new RemoteControlReader( 201 mockConnection.getSocketB().getInputStream()); 202 203 final ExecutionDataStore execStore = new ExecutionDataStore(); 204 remoteReader.setExecutionDataVisitor(execStore); 205 final SessionInfoStore infoStore = new SessionInfoStore(); 206 remoteReader.setSessionInfoVisitor(infoStore); 207 208 assertTrue(remoteReader.read()); 209 210 final List<SessionInfo> infos = infoStore.getInfos(); 211 assertEquals(1, infos.size()); 212 assertEquals("stubid", infos.get(0).getId()); 213 214 assertEquals("Foo", execStore.get(0x12345678).getName()); 215 } 216 217 @Test 218 public void testRemoteReset() throws Exception { 219 data.getExecutionData(Long.valueOf(123), "Foo", 1) 220 .getProbes()[0] = true; 221 222 final RemoteControlWriter remoteWriter = new RemoteControlWriter( 223 mockConnection.getSocketB().getOutputStream()); 224 225 final TcpConnection con = new TcpConnection(mockConnection.getSocketA(), 226 data); 227 con.init(); 228 229 final Future<Void> f = executor.submit(new Callable<Void>() { 230 public Void call() throws Exception { 231 con.run(); 232 return null; 233 } 234 }); 235 236 assertBlocks(f); 237 238 remoteWriter.visitDumpCommand(false, true); 239 240 final RemoteControlReader remoteReader = new RemoteControlReader( 241 mockConnection.getSocketB().getInputStream()); 242 243 final ExecutionDataStore execStore = new ExecutionDataStore(); 244 remoteReader.setExecutionDataVisitor(execStore); 245 final SessionInfoStore infoStore = new SessionInfoStore(); 246 remoteReader.setSessionInfoVisitor(infoStore); 247 248 assertTrue(remoteReader.read()); 249 assertTrue(infoStore.getInfos().isEmpty()); 250 assertTrue(execStore.getContents().isEmpty()); 251 assertFalse(data.getExecutionData(Long.valueOf(123), "Foo", 1) 252 .getProbes()[0]); 253 254 con.close(); 255 f.get(); 256 } 257 258 } 259