/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation: version 3 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package org.ow2.proactive_grid_cloud_portal.scheduler;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.net.URI;
import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.jboss.resteasy.client.ProxyFactory;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.ow2.proactive.scheduler.common.exception.NotConnectedException;
import org.ow2.proactive.scheduler.common.exception.PermissionException;
import org.ow2.proactive.scheduler.common.exception.UnknownJobException;
import org.ow2.proactive.scheduler.common.task.Log4JTaskLogs;
import org.ow2.proactive.scheduler.common.util.SchedulerProxyUserInterface;
import org.ow2.proactive.scheduler.common.util.logforwarder.AppenderProvider;
import org.ow2.proactive.scheduler.common.util.logforwarder.LogForwardingException;
import org.ow2.proactive.scheduler.common.util.logforwarder.LogForwardingProvider;
import org.ow2.proactive.scheduler.common.util.logforwarder.LoggingEventProcessor;
import org.ow2.proactive_grid_cloud_portal.RestTestServer;
import org.ow2.proactive_grid_cloud_portal.common.SchedulerRestInterface;
import org.ow2.proactive_grid_cloud_portal.common.SharedSessionStoreTestUtils;
import org.ow2.proactive_grid_cloud_portal.webapp.PortalConfiguration;
public class SchedulerStateRestLiveLogsTest extends RestTestServer {
private SchedulerRestInterface client;
private SchedulerProxyUserInterface scheduler;
private String sessionId;
@BeforeClass
public static void setUpRest() throws Exception {
addResource(new SchedulerStateRest());
}
@Before
public void setUp() throws Exception {
client = ProxyFactory.create(SchedulerRestInterface.class, "http://localhost:" + port + "/");
PortalConfiguration.SCHEDULER_LOGINFORWARDINGSERVICE_PROVIDER.updateProperty(SynchronousLocalLogForwardingProvider.class.getName());
scheduler = mock(SchedulerProxyUserInterface.class);
sessionId = SharedSessionStoreTestUtils.createValidSession(scheduler);
}
@Test
public void testLiveLogs_OutputRemovedAtEachCall() throws Exception {
String firstJobId = "42";
String firstJobLogs = client.getLiveLogJob(sessionId, firstJobId);
Appender appender = verifyListenAndGetAppender("42");
assertTrue(firstJobLogs.isEmpty());
appender.doAppend(createLoggingEvent(firstJobId, "first log"));
firstJobLogs = client.getLiveLogJob(sessionId, firstJobId);
assertThat(firstJobLogs, containsString("first log"));
appender.doAppend(createLoggingEvent(firstJobId, "other log"));
firstJobLogs = client.getLiveLogJob(sessionId, firstJobId);
assertThat(firstJobLogs, not(containsString("first log")));
assertThat(firstJobLogs, containsString("other log"));
firstJobLogs = client.getLiveLogJob(sessionId, firstJobId);
assertTrue(firstJobLogs.isEmpty());
}
private Appender verifyListenAndGetAppender(String jobId)
throws NotConnectedException, UnknownJobException, PermissionException, LogForwardingException {
ArgumentCaptor<AppenderProvider> appenderProviderArgumentCaptor = ArgumentCaptor.forClass(AppenderProvider.class);
verify(scheduler).listenJobLogs(eq(jobId), appenderProviderArgumentCaptor.capture());
AppenderProvider appenderProvider = appenderProviderArgumentCaptor.getValue();
return appenderProvider.getAppender();
}
private LoggingEvent createLoggingEvent(String firstJobId, String message) {
return new LoggingEvent(null,
Logger.getLogger(Log4JTaskLogs.JOB_LOGGER_PREFIX + firstJobId),
Level.DEBUG,
message,
null);
}
@Test
public void testLiveLogs_TwoJobsAtTheSameTime() throws Exception {
String firstJobId = "42";
String secondJobId = "43";
String firstJobLogs = client.getLiveLogJob(sessionId, firstJobId);
Appender firstAppender = verifyListenAndGetAppender(firstJobId);
String secondJobLogs = client.getLiveLogJob(sessionId, secondJobId);
Appender secondAppender = verifyListenAndGetAppender(secondJobId);
assertTrue(firstJobLogs.isEmpty());
assertTrue(secondJobLogs.isEmpty());
firstAppender.doAppend(createLoggingEvent(firstJobId, "first job"));
secondAppender.doAppend(createLoggingEvent(secondJobId, "second job"));
firstJobLogs = client.getLiveLogJob(sessionId, firstJobId);
assertThat(firstJobLogs, containsString("first job"));
secondJobLogs = client.getLiveLogJob(sessionId, secondJobId);
assertThat(secondJobLogs, containsString("second job"));
}
@Test
public void testLiveLogs_AvailableAndDelete() throws Exception {
String firstJobId = "42";
assertEquals(-1, client.getLiveLogJobAvailable(sessionId, "42"));
String logs = client.getLiveLogJob(sessionId, firstJobId);
Appender appender = verifyListenAndGetAppender("42");
assertEquals(0, client.getLiveLogJobAvailable(sessionId, "42"));
assertTrue(logs.isEmpty());
appender.doAppend(createLoggingEvent(firstJobId, "first log"));
assertEquals(1, client.getLiveLogJobAvailable(sessionId, "42"));
assertTrue(client.deleteLiveLogJob(sessionId, "42"));
assertEquals(-1, client.getLiveLogJobAvailable(sessionId, "42"));
// will be lost
appender.doAppend(createLoggingEvent(firstJobId, "second log"));
logs = client.getLiveLogJob(sessionId, firstJobId);
assertTrue(logs.isEmpty());
appender.doAppend(createLoggingEvent(firstJobId, "other log"));
appender.doAppend(createLoggingEvent(firstJobId, "more log"));
assertEquals(2, client.getLiveLogJobAvailable(sessionId, "42"));
logs = client.getLiveLogJob(sessionId, firstJobId);
assertThat(logs, not(containsString("first log")));
assertThat(logs, containsString("other log"));
assertThat(logs, containsString("more log"));
assertEquals(0, client.getLiveLogJobAvailable(sessionId, "42"));
logs = client.getLiveLogJob(sessionId, firstJobId);
assertTrue(logs.isEmpty());
}
public static class SynchronousLocalLogForwardingProvider implements LogForwardingProvider {
private LoggingEventProcessor eventProcessor;
@Override
public AppenderProvider createAppenderProvider(URI serverURI) throws LogForwardingException {
return new AppenderProvider() {
@Override
public Appender getAppender() throws LogForwardingException {
return new AppenderSkeleton() {
@Override
protected void append(LoggingEvent event) {
eventProcessor.processEvent(event);
}
@Override
public boolean requiresLayout() {
return false;
}
@Override
public void close() {
}
};
}
};
}
@Override
public URI createServer(LoggingEventProcessor eventProcessor) throws LogForwardingException {
this.eventProcessor = eventProcessor;
return null;
}
@Override
public void terminateServer() throws LogForwardingException {
}
}
}