package org.yamcs.management;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.yamcs.TmPacketProvider;
import org.yamcs.TmProcessor;
import org.yamcs.Processor;
import org.yamcs.ProcessorClient;
import org.yamcs.ProcessorException;
import org.yamcs.YConfiguration;
import org.yamcs.YamcsServer;
import org.yamcs.management.ManagementService;
import org.yamcs.security.AuthenticationToken;
import org.yamcs.ui.ProcessorControlClient;
import org.yamcs.ui.ProcessorListener;
import org.yamcs.ui.YamcsConnector;
import org.yamcs.api.YamcsApiException;
import org.yamcs.api.YamcsConnectionProperties;
import org.yamcs.protobuf.YamcsManagement.ProcessorInfo;
import org.yamcs.protobuf.Web.RestExceptionMessage;
import org.yamcs.protobuf.YamcsManagement.ClientInfo;
import org.yamcs.protobuf.YamcsManagement.ServiceState;
import org.yamcs.protobuf.YamcsManagement.Statistics;
import com.google.common.util.concurrent.AbstractService;
import static org.junit.Assert.*;
public class ProcessorsTest {
// static EmbeddedActiveMQ artemisServer;
@BeforeClass
public static void setupHornetAndManagement() throws Exception {
ManagementService.setup(false);
YConfiguration.setup("ProcessorsTest");
YamcsServer.setupYamcsServer();
//Logger.getLogger("org.yamcs").setLevel(Level.ALL);
}
@AfterClass
public static void afterClass() throws Exception {
ManagementService.getInstance().shutdown();
YamcsServer.shutDown();
}
@Test
public void createProcessorWithoutClient() throws Exception {
YamcsConnector yconnector = new YamcsConnector("ProcessorTest");
ProcessorControlClient ccc = new ProcessorControlClient(yconnector);
ccc.setProcessorListener(new MyListener("YProcessorsTest"));
yconnector.connect(YamcsConnectionProperties.parse("http://localhost:28090/")).get(5,TimeUnit.SECONDS);
try {
ccc.createProcessor("yproctest0", "test1", "dummy", null, false, new int[]{10,14}).get();
assertTrue("YamcsException was expected", false);
} catch(ExecutionException e) {
RestExceptionMessage rem = ((YamcsApiException)e.getCause()).getRestExceptionMessage();
assertEquals("createProcessor invoked with a list full of invalid client ids", rem.getMsg());
}
yconnector.disconnect();
}
@Test
public void createAndSwitchProcessor() throws Exception {
YamcsConnector yconnector = new YamcsConnector("ProcessorTest-randname1");
ProcessorControlClient client1 = new ProcessorControlClient(yconnector);
MyListener ml=new MyListener("yproctest1");
client1.setProcessorListener(ml);
Future<YamcsConnectionProperties> f = yconnector.connect(YamcsConnectionProperties.parse("http://localhost:28090/yproctest1"));
f.get(5, TimeUnit.SECONDS);
Thread.sleep(3000);
client1.createProcessor("yproctest1", "yproc1", "dummy", null, true, new int[]{}).get();
MyYProcClient client = new MyYProcClient();
Processor yproc1 = Processor.getInstance("yproctest1", "yproc1");
assertNotNull(yproc1);
yproc1.connect(client);
client.yproc = yproc1;
int myClientId = ManagementService.getInstance().registerClient("yproctest1", "yproc1", client);
assertNotNull(ManagementService.getInstance().getClientInfo(myClientId));
client1.createProcessor("yproctest1", "yproc2", "dummy", null, false, new int[]{myClientId}).get();
assertNotNull(ManagementService.getInstance().getClientInfo(myClientId));
//this one should trigger the closing of non permanent yproc2 because no more client connected
CompletableFuture<Void> f1= client1.connectToProcessor("yproctest1", "yproc1", new int[]{myClientId});
f1.get();
yproc1.disconnect(client);
ManagementService.getInstance().unregisterClient(myClientId);
yproc1.quit();
assertNull(ManagementService.getInstance().getClientInfo(myClientId));
yconnector.disconnect();
Thread.sleep(3000);//to allow for events to come
/* for(ProcessorInfo pi: ml.yprocUpdated) {
System.out.println("\t"+pi.getInstance()+"/"+pi.getName()+" state: "+pi.getState()+" replayState: "+pi.getReplayState());
}*/
List<ProcessorInfo> l = ml.yprocUpdated.get("realtime");
assertEquals(1, l.size());
assertPEquals("realtime", ServiceState.RUNNING, l.get(0));
l = ml.yprocUpdated.get("yproc1");
assertEquals(3, l.size());
assertPEquals("yproc1", ServiceState.NEW, l.get(0));
assertPEquals("yproc1", ServiceState.RUNNING, l.get(1));
assertPEquals("yproc1", ServiceState.STOPPING, l.get(2));
l = ml.yprocUpdated.get("yproc2");
assertEquals(3, l.size());
assertPEquals("yproc2", ServiceState.NEW, l.get(0));
assertPEquals("yproc2", ServiceState.RUNNING, l.get(1));
assertPEquals("yproc2", ServiceState.STOPPING, l.get(2));
assertEquals(4, ml.clientUpdatedList.size());
//first one is from the ProcessorControlClient
assertCEquals("yproctest1", "realtime",myClientId-1, "admin", "ProcessorTest-randname1", ml.clientUpdatedList.get(0));
assertCEquals("yproctest1", "yproc1",myClientId, "random-test-user", "random-app-name", ml.clientUpdatedList.get(1));
assertCEquals("yproctest1", "yproc2",myClientId, "random-test-user", "random-app-name", ml.clientUpdatedList.get(2));
assertCEquals("yproctest1", "yproc1",myClientId, "random-test-user", "random-app-name", ml.clientUpdatedList.get(3));
}
private void assertCEquals(String instance, String procName, int clientId, String username, String appname, ClientInfo clientInfo) {
assertEquals(instance, clientInfo.getInstance());
assertEquals(procName, clientInfo.getProcessorName());
assertEquals(clientId, clientInfo.getId());
assertEquals(username, clientInfo.getUsername());
assertEquals(appname, clientInfo.getApplicationName());
}
private void assertPEquals(String procName, ServiceState state, ProcessorInfo processorInfo) {
assertEquals(procName, processorInfo.getName());
assertEquals(state, processorInfo.getState());
}
static class MyListener implements ProcessorListener {
Map<String, List<ProcessorInfo>> yprocUpdated = new HashMap<>();
List<ProcessorInfo> yprocClosedList=Collections.synchronizedList(new ArrayList<ProcessorInfo>());
List<ClientInfo> clientUpdatedList=Collections.synchronizedList(new ArrayList<ClientInfo>());
List<ClientInfo> clientDisconnectedList=Collections.synchronizedList(new ArrayList<ClientInfo>());
String instance;
public MyListener(String instance) {
this.instance=instance;
}
@Override
public void log(String text) {
System.out.println("log: "+text);
}
@Override
public void popup(String text) {
// TODO Auto-generated method stub
}
@Override
public void processorUpdated(ProcessorInfo pi) {
if(instance.equals(pi.getInstance())) {
List<ProcessorInfo> l = yprocUpdated.get(pi.getName());
if(l==null) {
l = new ArrayList<ProcessorInfo>();
yprocUpdated.put(pi.getName(), l);
}
l.add(pi);
}
}
@Override
public void processorClosed(ProcessorInfo ci) {
if(instance.equals(ci.getInstance()))
yprocClosedList.add(ci);
}
@Override
public void clientUpdated(ClientInfo ci) {
if(instance.equals(ci.getInstance())) {
clientUpdatedList.add(ci);
}
}
@Override
public void clientDisconnected(ClientInfo ci) {
if(instance.equals(ci.getInstance())) {
clientDisconnectedList.add(ci);
}
}
@Override
public void updateStatistics(Statistics s) {
// TODO Auto-generated method stub
}
}
static class MyYProcClient implements ProcessorClient {
Processor yproc;
@Override
public void switchProcessor(Processor c, AuthenticationToken authToken) throws ProcessorException {
yproc.disconnect(this);
c.connect(this);
yproc=c;
}
@Override
public void processorQuit() {
// TODO Auto-generated method stub
}
@Override
public String getUsername() {
return "random-test-user";
}
@Override
public String getApplicationName() {
return "random-app-name";
}
}
public static class DummyTmProvider extends AbstractService implements TmPacketProvider {
private TmProcessor tmProcessor;
public DummyTmProvider(String instance) {
}
@Override
public boolean isArchiveReplay() {
return false;
}
@Override
public void doStop() {
tmProcessor.finished();
notifyStopped();
}
@Override
protected void doStart() {
notifyStarted();
}
@Override
public void init(Processor proc, TmProcessor tmProcessor) {
this.tmProcessor = tmProcessor;
}
}
}