mirror of https://github.com/rusefi/rusefi.git
207 lines
9.0 KiB
Java
207 lines
9.0 KiB
Java
package com.rusefi.proxy.client;
|
|
|
|
import com.rusefi.BackendTestHelper;
|
|
import com.rusefi.TestHelper;
|
|
import com.rusefi.Timeouts;
|
|
import com.rusefi.config.generated.Fields;
|
|
import com.rusefi.io.IoStream;
|
|
import com.rusefi.io.commands.GetOutputsCommand;
|
|
import com.rusefi.io.commands.HelloCommand;
|
|
import com.rusefi.io.tcp.BinaryProtocolServer;
|
|
import com.rusefi.io.tcp.ServerSocketReference;
|
|
import com.rusefi.io.tcp.TcpIoStream;
|
|
import com.rusefi.server.ApplicationRequest;
|
|
import com.rusefi.server.SessionDetails;
|
|
import com.rusefi.tools.online.ProxyClient;
|
|
import com.rusefi.ui.StatusConsumer;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
|
|
import java.io.IOException;
|
|
import java.net.MalformedURLException;
|
|
import java.net.Socket;
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import static com.rusefi.BackendTestHelper.createTestUserResolver;
|
|
import static com.rusefi.TestHelper.*;
|
|
import static com.rusefi.Timeouts.SECOND;
|
|
import static com.rusefi.binaryprotocol.BinaryProtocol.findCommand;
|
|
import static com.rusefi.binaryprotocol.BinaryProtocol.sleep;
|
|
import static com.rusefi.config.generated.Fields.TS_PROTOCOL;
|
|
import static com.rusefi.io.tcp.BinaryProtocolServer.getPacketLength;
|
|
import static com.rusefi.io.tcp.TcpConnector.LOCALHOST;
|
|
import static com.rusefi.core.FileUtil.close;
|
|
import static org.junit.Assert.*;
|
|
|
|
public class LocalApplicationProxyTest {
|
|
private static final AtomicInteger portNumber = new AtomicInteger(4000);
|
|
|
|
@Before
|
|
public void setup() throws MalformedURLException {
|
|
BackendTestHelper.commonServerTest();
|
|
}
|
|
|
|
@Test
|
|
public void testDisconnectCallback() throws IOException, InterruptedException {
|
|
LocalApplicationProxyContext context = createLocalApplicationProxy();
|
|
|
|
CountDownLatch backendCreated = new CountDownLatch(1);
|
|
ServerSocketReference mockBackend = BinaryProtocolServer.tcpServerSocket(context.serverPortForRemoteApplications(), "localAppTest", socket -> () -> {
|
|
sleep(Timeouts.SECOND);
|
|
close(socket);
|
|
}, parameter -> backendCreated.countDown(), StatusConsumer.ANONYMOUS);
|
|
assertLatch(backendCreated);
|
|
|
|
SessionDetails sessionDetails = TestHelper.createTestSession(TEST_TOKEN_1, Fields.TS_SIGNATURE);
|
|
ApplicationRequest applicationRequest = new ApplicationRequest(sessionDetails, createTestUserResolver().apply(TEST_TOKEN_1));
|
|
|
|
CountDownLatch disconnected = new CountDownLatch(1);
|
|
LocalApplicationProxy.startAndRun(context, applicationRequest, -1, (String message) -> disconnected.countDown(), LocalApplicationProxy.ConnectionListener.VOID);
|
|
|
|
assertLatch(disconnected);
|
|
mockBackend.close();
|
|
}
|
|
|
|
@Test
|
|
public void testCommandProtocol() throws IOException, InterruptedException {
|
|
LocalApplicationProxyContext context = createLocalApplicationProxy();
|
|
CountDownLatch gaugePokes = new CountDownLatch(3);
|
|
|
|
try (ServerSocketReference ignored1 = createMockBackend(context, gaugePokes)) {
|
|
SessionDetails sessionDetails = TestHelper.createTestSession(TEST_TOKEN_1, Fields.TS_SIGNATURE);
|
|
ApplicationRequest applicationRequest = new ApplicationRequest(sessionDetails, createTestUserResolver().apply(TEST_TOKEN_1));
|
|
|
|
try (ServerSocketReference ignored2 = LocalApplicationProxy.startAndRun(context, applicationRequest, -1, TcpIoStream.DisconnectListener.VOID, LocalApplicationProxy.ConnectionListener.VOID)) {
|
|
TcpIoStream applicationConnection = new TcpIoStream("mock application ", new Socket(LOCALHOST, context.authenticatorPort()));
|
|
|
|
byte[] protocolResponse = new byte[TS_PROTOCOL.length()];
|
|
// request
|
|
applicationConnection.write(new byte[] {Fields.TS_COMMAND_F});
|
|
applicationConnection.flush();
|
|
// response
|
|
applicationConnection.getDataBuffer().read(protocolResponse);
|
|
assertArrayEquals(protocolResponse, TS_PROTOCOL.getBytes());
|
|
|
|
// request again
|
|
applicationConnection.write(new byte[] {Fields.TS_COMMAND_F});
|
|
applicationConnection.flush();
|
|
// response again
|
|
applicationConnection.getDataBuffer().read(protocolResponse);
|
|
assertArrayEquals(protocolResponse, TS_PROTOCOL.getBytes());
|
|
|
|
// TODO: why is this logic duplicated from BinaryProtocol?
|
|
byte[] commandPacket = new byte[5];
|
|
commandPacket[0] = Fields.TS_OUTPUT_COMMAND;
|
|
System.arraycopy(GetOutputsCommand.createRequest(), 0, commandPacket, 1, 4);
|
|
|
|
applicationConnection.sendPacket(commandPacket);
|
|
BinaryProtocolServer.Packet response = applicationConnection.readPacket();
|
|
assertEquals(Fields.TS_TOTAL_OUTPUT_SIZE + 1, response.getPacket().length);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testGaugePoking() throws IOException, InterruptedException {
|
|
LocalApplicationProxyContext context = createLocalApplicationProxy();
|
|
|
|
CountDownLatch gaugePokes = new CountDownLatch(3);
|
|
|
|
try (ServerSocketReference ignored1 = createMockBackend(context, gaugePokes)) {
|
|
|
|
SessionDetails sessionDetails = TestHelper.createTestSession(TEST_TOKEN_1, Fields.TS_SIGNATURE);
|
|
ApplicationRequest applicationRequest = new ApplicationRequest(sessionDetails, createTestUserResolver().apply(TEST_TOKEN_1));
|
|
|
|
CountDownLatch disconnected = new CountDownLatch(1);
|
|
|
|
try (ServerSocketReference ignored2 = LocalApplicationProxy.startAndRun(context, applicationRequest, -1, (String message) -> disconnected.countDown(), LocalApplicationProxy.ConnectionListener.VOID)) {
|
|
|
|
// wait for three output requests to take place
|
|
assertLatch("gaugePokes", gaugePokes);
|
|
|
|
// but there must be a disconnect after some time
|
|
assertLatch("disconnected", disconnected);
|
|
}
|
|
}
|
|
}
|
|
|
|
@NotNull
|
|
private static ServerSocketReference createMockBackend(LocalApplicationProxyContext context, CountDownLatch gaugePokes) throws IOException, InterruptedException {
|
|
CountDownLatch backendCreated = new CountDownLatch(1);
|
|
ServerSocketReference mockBackend = BinaryProtocolServer.tcpServerSocket(context.serverPortForRemoteApplications(), "localAppTest", socket -> () -> {
|
|
try {
|
|
IoStream applicationClientStream = new TcpIoStream("gauge", socket);
|
|
|
|
HelloCommand.getHelloResponse(applicationClientStream.getDataBuffer());
|
|
|
|
while (!socket.isClosed()) {
|
|
AtomicBoolean handled = new AtomicBoolean();
|
|
|
|
int length = getPacketLength(applicationClientStream.getDataBuffer(), new BinaryProtocolServer.Handler() {
|
|
@Override
|
|
public void handle() throws IOException {
|
|
applicationClientStream.write(TS_PROTOCOL.getBytes());
|
|
handled.set(true);
|
|
}
|
|
});
|
|
if (handled.get())
|
|
continue;
|
|
|
|
BinaryProtocolServer.Packet packet = BinaryProtocolServer.readPromisedBytes(applicationClientStream.getDataBuffer(), length);
|
|
System.out.println("Got packet " + findCommand(packet.getPacket()[0]));
|
|
|
|
if (packet.getPacket().length != 5)
|
|
throw new IllegalStateException("Unexpected length " + packet.getPacket().length);
|
|
|
|
GetOutputsCommand.sendOutput(applicationClientStream);
|
|
gaugePokes.countDown();
|
|
}
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
|
|
}, parameter -> backendCreated.countDown(), StatusConsumer.ANONYMOUS);
|
|
|
|
assertLatch(backendCreated);
|
|
return mockBackend;
|
|
}
|
|
|
|
@NotNull
|
|
private LocalApplicationProxyContext createLocalApplicationProxy() {
|
|
return new LocalApplicationProxyContext() {
|
|
private final int remotePort = portNumber.incrementAndGet();
|
|
private final int authenticatorPort = portNumber.incrementAndGet();
|
|
|
|
@Override
|
|
public String executeGet(String url) {
|
|
if (url.endsWith(ProxyClient.VERSION_PATH))
|
|
return ProxyClient.BACKEND_VERSION;
|
|
throw new UnsupportedOperationException(url);
|
|
}
|
|
|
|
@Override
|
|
public int serverPortForRemoteApplications() {
|
|
return remotePort;
|
|
}
|
|
|
|
@Override
|
|
public int authenticatorPort() {
|
|
return authenticatorPort;
|
|
}
|
|
|
|
@Override
|
|
public int startUpIdle() {
|
|
return 7 * Timeouts.SECOND;
|
|
}
|
|
|
|
@Override
|
|
public int gaugePokingPeriod() {
|
|
return SECOND;
|
|
}
|
|
};
|
|
}
|
|
}
|