/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.serviceregistry.impl;
import static com.entwinemedia.fn.Stream.$;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.opencastproject.util.data.Arrays.mkString;
import static org.opencastproject.util.data.Monadics.mlist;
import static org.opencastproject.util.data.functions.Booleans.eq;
import static org.opencastproject.util.persistence.PersistenceEnvs.persistenceEnvironment;
import static org.opencastproject.util.persistence.PersistenceUtil.newTestEntityManagerFactory;
import org.opencastproject.job.api.JaxbJob;
import org.opencastproject.job.api.Job;
import org.opencastproject.job.api.Job.FailureReason;
import org.opencastproject.job.api.Job.Status;
import org.opencastproject.job.api.JobImpl;
import org.opencastproject.job.api.JobParser;
import org.opencastproject.mediapackage.MediaPackageElementBuilderFactory;
import org.opencastproject.mediapackage.MediaPackageElementParser;
import org.opencastproject.mediapackage.MediaPackageElements;
import org.opencastproject.mediapackage.Track;
import org.opencastproject.security.api.DefaultOrganization;
import org.opencastproject.security.api.JaxbOrganization;
import org.opencastproject.security.api.JaxbRole;
import org.opencastproject.security.api.JaxbUser;
import org.opencastproject.security.api.Organization;
import org.opencastproject.security.api.OrganizationDirectoryService;
import org.opencastproject.security.api.SecurityService;
import org.opencastproject.security.api.User;
import org.opencastproject.serviceregistry.api.ServiceRegistration;
import org.opencastproject.serviceregistry.impl.jpa.ServiceRegistrationJpaImpl;
import org.opencastproject.util.UrlSupport;
import org.opencastproject.util.data.Function;
import org.opencastproject.util.data.Monadics;
import org.opencastproject.util.persistence.PersistenceEnv;
import com.entwinemedia.fn.Fn;
import com.entwinemedia.fn.Stream;
import org.apache.commons.lang3.StringUtils;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
public class JobTest {
private static final String JOB_TYPE_1 = "testing1";
private static final String JOB_TYPE_2 = "testing2";
private static final String OPERATION_NAME = "op";
private static final String LOCALHOST = UrlSupport.DEFAULT_BASE_URL;
private static final String REMOTEHOST = "http://remotehost:8080";
private static final String PATH = "/path";
private ServiceRegistryJpaImpl serviceRegistry = null;
private ServiceRegistrationJpaImpl regType1Localhost = null;
private ServiceRegistrationJpaImpl regType1Remotehost = null;
private ServiceRegistrationJpaImpl regType2Localhost = null;
@SuppressWarnings("unused")
private ServiceRegistrationJpaImpl regType2Remotehost = null;
private PersistenceEnv penv;
@Before
public void setUp() throws Exception {
final EntityManagerFactory emf = newTestEntityManagerFactory(ServiceRegistryJpaImpl.PERSISTENCE_UNIT);
serviceRegistry = new ServiceRegistryJpaImpl();
serviceRegistry.setEntityManagerFactory(emf);
serviceRegistry.activate(null);
Organization organization = new DefaultOrganization();
OrganizationDirectoryService organizationDirectoryService = EasyMock.createMock(OrganizationDirectoryService.class);
EasyMock.expect(organizationDirectoryService.getOrganization((String) EasyMock.anyObject()))
.andReturn(organization).anyTimes();
EasyMock.replay(organizationDirectoryService);
serviceRegistry.setOrganizationDirectoryService(organizationDirectoryService);
JaxbOrganization jaxbOrganization = JaxbOrganization.fromOrganization(organization);
User anonymous = new JaxbUser("anonymous", "test", jaxbOrganization, new JaxbRole(
jaxbOrganization.getAnonymousRole(), jaxbOrganization));
SecurityService securityService = EasyMock.createNiceMock(SecurityService.class);
EasyMock.expect(securityService.getUser()).andReturn(anonymous).anyTimes();
EasyMock.expect(securityService.getOrganization()).andReturn(organization).anyTimes();
EasyMock.replay(securityService);
serviceRegistry.setSecurityService(securityService);
// register the hosts
serviceRegistry.registerHost(LOCALHOST, "127.0.0.1", 1024, 1, 1.0f);
serviceRegistry.registerHost(REMOTEHOST, "127.0.0.1", 1024, 1, 1.0f);
// register some service instances
regType1Localhost = (ServiceRegistrationJpaImpl) serviceRegistry.registerService(JOB_TYPE_1, LOCALHOST, PATH);
regType1Remotehost = (ServiceRegistrationJpaImpl) serviceRegistry.registerService(JOB_TYPE_1, REMOTEHOST, PATH);
regType2Localhost = (ServiceRegistrationJpaImpl) serviceRegistry.registerService(JOB_TYPE_2, LOCALHOST, PATH);
regType2Remotehost = (ServiceRegistrationJpaImpl) serviceRegistry.registerService(JOB_TYPE_2, REMOTEHOST, PATH);
penv = persistenceEnvironment(emf);
}
@After
public void tearDown() throws Exception {
serviceRegistry.unRegisterService(JOB_TYPE_1, LOCALHOST);
serviceRegistry.unRegisterService(JOB_TYPE_1, REMOTEHOST);
serviceRegistry.unRegisterService(JOB_TYPE_2, LOCALHOST);
serviceRegistry.unRegisterService(JOB_TYPE_2, REMOTEHOST);
serviceRegistry.deactivate();
}
@Test
public void testGetJob() throws Exception {
// Start a job, but don't allow it to be dispatched
Job job = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false, 4.0f);
Assert.assertNotNull(job.getUri());
Job jobFromDb = serviceRegistry.getJob(job.getId());
assertEquals(Status.INSTANTIATED, jobFromDb.getStatus());
assertEquals(new Float(4.0f), job.getJobLoad());
// Simulate starting the job
job.setStatus(Status.RUNNING);
job = serviceRegistry.updateJob(job);
// Finish the job
job = serviceRegistry.getJob(job.getId());
Track t = (Track) MediaPackageElementBuilderFactory.newInstance().newElementBuilder()
.elementFromURI(new URI("file://test.mov"), Track.TYPE, MediaPackageElements.PRESENTATION_SOURCE);
t.setIdentifier("track-1");
job.setPayload(MediaPackageElementParser.getAsXml(t));
job.setStatus(Status.FINISHED);
job = serviceRegistry.updateJob(job);
jobFromDb = serviceRegistry.getJob(job.getId());
Assert.assertNotNull(jobFromDb.getUri());
assertEquals(job.getPayload(), jobFromDb.getPayload());
}
@Test
public void testGetJobs() throws Exception {
Job job = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, null);
job.setStatus(Status.RUNNING);
job = serviceRegistry.updateJob(job);
long id = job.getId();
// Search using both the job type and status
List<Job> jobs = serviceRegistry.getJobs(JOB_TYPE_1, Status.RUNNING);
assertEquals(1, jobs.size());
// Search using just the job type
jobs = serviceRegistry.getJobs(JOB_TYPE_1, null);
assertEquals(1, jobs.size());
// Search using just the status
jobs = serviceRegistry.getJobs(null, Status.RUNNING);
assertEquals(1, jobs.size());
// Search using nulls (return everything)
jobs = serviceRegistry.getJobs(null, null);
assertEquals(1, jobs.size());
Job receipt = serviceRegistry.getJob(id);
receipt.setStatus(Status.FINISHED);
receipt = serviceRegistry.updateJob(receipt);
long queuedJobs = serviceRegistry.count(JOB_TYPE_1, Status.RUNNING);
assertEquals(0, queuedJobs);
}
@Test
public void testGetActiveJobs() throws Exception {
Job job = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, null);
job.setStatus(Status.RUNNING);
job = serviceRegistry.updateJob(job);
job = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_2, OPERATION_NAME, null, null, false, null);
job.setStatus(Status.RUNNING);
job = serviceRegistry.updateJob(job);
// Search using both the job type and status
List<Job> jobs = serviceRegistry.getActiveJobs();
assertEquals(2, jobs.size());
long jobId = jobs.get(0).getId();
for (Status status : Status.values()) {
job = serviceRegistry.getJob(jobId);
job.setStatus(status);
serviceRegistry.updateJob(job);
jobs = serviceRegistry.getActiveJobs();
if (status.isActive())
assertEquals(2, jobs.size());
else
assertEquals(1, jobs.size());
}
}
@Test
public void testGetChildJobs() throws Exception {
Job rootJob = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, null);
Job job = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, rootJob);
Job job1 = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, job);
Job job3 = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, job);
Job job4 = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, job3);
Job job2 = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, job1);
Job job5 = serviceRegistry.createJob(LOCALHOST, JOB_TYPE_1, OPERATION_NAME, null, null, false, job4);
job = serviceRegistry.updateJob(job);
job1 = serviceRegistry.updateJob(job1);
job2 = serviceRegistry.updateJob(job2);
job3 = serviceRegistry.updateJob(job3);
job4 = serviceRegistry.updateJob(job4);
job5 = serviceRegistry.updateJob(job5);
// Search children by root job
final Stream<Job> rootChildren = $(serviceRegistry.getChildJobs(rootJob.getId()));
assertEquals(6, rootChildren.getSizeHint());
assertTrue(rootChildren.exists(matchesId(job)));
assertTrue(rootChildren.exists(matchesId(job1)));
assertTrue(rootChildren.exists(matchesId(job2)));
assertTrue(rootChildren.exists(matchesId(job3)));
assertTrue(rootChildren.exists(matchesId(job4)));
assertTrue(rootChildren.exists(matchesId(job5)));
// Search children
final Stream<Job> jobChildren = $(serviceRegistry.getChildJobs(job.getId()));
assertEquals(5, jobChildren.getSizeHint());
assertTrue(jobChildren.exists(matchesId(job1)));
assertTrue(jobChildren.exists(matchesId(job2)));
assertTrue(jobChildren.exists(matchesId(job3)));
assertTrue(jobChildren.exists(matchesId(job4)));
assertTrue(jobChildren.exists(matchesId(job5)));
}
private static Fn<Job, Boolean> matchesId(final Job j) {
return new Fn<Job, Boolean>() {
@Override
public Boolean apply(Job job) {
return job.getId() == j.getId();
}
};
}
@Test
public void testCount() throws Exception {
// create a receipt on each service instance
serviceRegistry.createJob(regType1Localhost.getHost(), regType1Localhost.getServiceType(), OPERATION_NAME, null,
null, false, null);
serviceRegistry.createJob(regType1Remotehost.getHost(), regType1Remotehost.getServiceType(), OPERATION_NAME, null,
null, false, null);
// Since these jobs have not been dispatched to a host, there shouldn't be any jobs on those hosts
assertEquals(1, serviceRegistry.countByHost(JOB_TYPE_1, LOCALHOST, Status.INSTANTIATED));
assertEquals(1, serviceRegistry.countByHost(JOB_TYPE_1, REMOTEHOST, Status.INSTANTIATED));
// Counting any job without regard to host should return both jobs
assertEquals(2, serviceRegistry.count(JOB_TYPE_1, Status.INSTANTIATED));
}
@Test
public void testCountByOperation() throws Exception {
// create a receipt on each service instance
serviceRegistry.createJob(regType1Localhost.getHost(), regType1Localhost.getServiceType(), OPERATION_NAME, null,
null, false, null);
serviceRegistry.createJob(regType1Remotehost.getHost(), regType1Remotehost.getServiceType(), OPERATION_NAME, null,
null, false, null);
// Counting any job without regard to host should return both jobs
assertEquals(2, serviceRegistry.countByOperation(JOB_TYPE_1, OPERATION_NAME, Status.INSTANTIATED));
}
@Test
public void testGetHostsCountWithNoJobs() throws Exception {
assertEquals(2, serviceRegistry.getServiceRegistrationsByLoad(JOB_TYPE_1).size());
assertEquals(2, serviceRegistry.getServiceRegistrationsByLoad(JOB_TYPE_2).size());
}
@Test
public void testNoJobServiceRegistrations() throws Exception {
List<ServiceRegistration> type1Hosts = serviceRegistry.getServiceRegistrationsByLoad(JOB_TYPE_1);
List<ServiceRegistration> type2Hosts = serviceRegistry.getServiceRegistrationsByLoad(JOB_TYPE_2);
assertEquals(2, type1Hosts.size());
assertEquals(2, type2Hosts.size());
}
@Test
public void testGetHostsCount() throws Exception {
Job localRunning1 = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false);
localRunning1.setStatus(Status.RUNNING);
localRunning1.setJobType(regType1Localhost.getServiceType());
localRunning1.setProcessingHost(regType1Localhost.getHost());
localRunning1 = serviceRegistry.updateJob(localRunning1);
Job localRunning2 = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false);
localRunning2.setStatus(Status.RUNNING);
localRunning2.setJobType(regType1Localhost.getServiceType());
localRunning2.setProcessingHost(regType1Localhost.getHost());
localRunning2 = serviceRegistry.updateJob(localRunning2);
Job localFinished = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false);
// Simulate starting the job
localFinished.setStatus(Status.RUNNING);
localFinished.setJobType(regType1Localhost.getServiceType());
localFinished.setProcessingHost(regType1Localhost.getHost());
localFinished = serviceRegistry.updateJob(localFinished);
// Finish the job
localFinished = serviceRegistry.getJob(localFinished.getId());
localFinished.setStatus(Status.FINISHED);
localFinished = serviceRegistry.updateJob(localFinished);
Job remoteRunning = serviceRegistry.createJob(regType1Remotehost.getHost(),
regType1Remotehost.getServiceType(), OPERATION_NAME, null, null, false, null);
remoteRunning.setStatus(Status.RUNNING);
remoteRunning.setJobType(regType1Remotehost.getServiceType());
remoteRunning.setProcessingHost(regType1Remotehost.getHost());
remoteRunning = serviceRegistry.updateJob(remoteRunning);
Job remoteFinished = serviceRegistry.createJob(regType1Remotehost.getHost(),
regType1Remotehost.getServiceType(), OPERATION_NAME, null, null, false, null);
// Simulate starting the job
remoteFinished.setStatus(Status.RUNNING);
remoteFinished.setJobType(regType1Remotehost.getServiceType());
remoteFinished.setProcessingHost(regType1Remotehost.getHost());
remoteFinished = serviceRegistry.updateJob(remoteFinished);
// Finish the job
remoteFinished = serviceRegistry.getJob(remoteFinished.getId());
remoteFinished.setStatus(Status.FINISHED);
remoteFinished = serviceRegistry.updateJob(remoteFinished);
Job otherTypeRunning = serviceRegistry.createJob(JOB_TYPE_2, OPERATION_NAME, null, null, false);
otherTypeRunning.setStatus(Status.RUNNING);
otherTypeRunning.setJobType(regType2Localhost.getServiceType());
otherTypeRunning.setProcessingHost(regType2Localhost.getHost());
otherTypeRunning = serviceRegistry.updateJob(otherTypeRunning);
Job otherTypeFinished = serviceRegistry .createJob(JOB_TYPE_2, OPERATION_NAME, null, null, false);
// Simulate starting the job
otherTypeFinished.setStatus(Status.RUNNING);
otherTypeFinished.setJobType(regType2Localhost.getServiceType());
otherTypeFinished.setProcessingHost(regType2Localhost.getHost());
otherTypeFinished = serviceRegistry.updateJob(otherTypeFinished);
// Finish the job
otherTypeFinished = serviceRegistry.getJob(otherTypeFinished.getId());
otherTypeFinished.setStatus(Status.FINISHED);
otherTypeFinished = serviceRegistry.updateJob(otherTypeFinished);
List<ServiceRegistration> type1Hosts = serviceRegistry.getServiceRegistrationsByLoad(JOB_TYPE_1);
List<ServiceRegistration> type2Hosts = serviceRegistry.getServiceRegistrationsByLoad(JOB_TYPE_2);
// The number of service registrations is equal on both hosts
assertEquals(2, type1Hosts.size());
assertEquals(2, type2Hosts.size());
// Count the number of jobs that are runnging
assertEquals(3, serviceRegistry.count(JOB_TYPE_1, Status.RUNNING));
assertEquals(1, serviceRegistry.count(JOB_TYPE_2, Status.RUNNING));
// Localhost has more jobs running than remotehost
assertEquals(REMOTEHOST, type1Hosts.get(0).getHost());
assertEquals(LOCALHOST, type1Hosts.get(1).getHost());
assertEquals(REMOTEHOST, type2Hosts.get(0).getHost());
assertEquals(LOCALHOST, type2Hosts.get(1).getHost());
}
@Test
public void testCountPerHostService() throws Exception {
// create some test data
testGetHostsCount();
// Add an additional dispatchable job. This is important as it leaves the processing host field empty.
Job localRunning1 = serviceRegistry.createJob(JOB_TYPE_2, OPERATION_NAME, null, null, true);
localRunning1.setStatus(Status.RUNNING);
localRunning1 = serviceRegistry.updateJob(localRunning1);
//
final Monadics.ListMonadic<String> jpql = resultToString(new Function.X<EntityManager, List<Object[]>>() {
@Override
public List<Object[]> xapply(EntityManager em) throws Exception {
return serviceRegistry.getCountPerHostService(em);
}
});
assertTrue(jpql.exists(eq("http://remotehost:8080,testing1,2,1")));
assertTrue(jpql.exists(eq("http://localhost:8080,testing2,2,2"))); // <-- 2 jobs, one of them is the
// dispatchable job
assertTrue(jpql.exists(eq("http://remotehost:8080,testing1,3,1")));
assertTrue(jpql.exists(eq("http://localhost:8080,testing2,3,1")));
assertTrue(jpql.exists(eq("http://localhost:8080,testing1,3,1")));
assertTrue(jpql.exists(eq("http://localhost:8080,testing1,2,2")));
assertEquals(6, jpql.value().size());
}
private Monadics.ListMonadic<String> resultToString(final Function<EntityManager, List<Object[]>> q) {
return penv.tx(new Function.X<EntityManager, Monadics.ListMonadic<String>>() {
@Override
protected Monadics.ListMonadic<String> xapply(EntityManager em) throws Exception {
// (host, service_type, status, count)
return mlist(q.apply(em)).map(new Function<Object[], String>() {
@Override
public String apply(Object[] a) {
return mkString(a, ",");
}
});
}
});
}
@Test
public void testHandlerRegistration() throws Exception {
String url = "http://type1handler:8080";
serviceRegistry.registerHost(url, "127.0.0.1", 1024, 1, 1);
String jobType = "type1";
// we should start with no handlers
List<ServiceRegistration> hosts = serviceRegistry.getServiceRegistrationsByLoad(jobType);
assertEquals(0, hosts.size());
// register a handler
serviceRegistry.registerService(jobType, url, PATH);
hosts = serviceRegistry.getServiceRegistrationsByLoad(jobType);
assertEquals(1, hosts.size());
assertEquals(url, hosts.get(0).getHost());
// set the handler to be in maintenance mode
serviceRegistry.setMaintenanceStatus(url, true);
hosts = serviceRegistry.getServiceRegistrationsByLoad(jobType);
assertEquals(0, hosts.size());
// set it back to normal mode
serviceRegistry.setMaintenanceStatus(url, false);
hosts = serviceRegistry.getServiceRegistrationsByLoad(jobType);
assertEquals(1, hosts.size());
// unregister
serviceRegistry.unRegisterService(jobType, url);
hosts = serviceRegistry.getServiceRegistrationsByLoad(jobType);
assertEquals(0, hosts.size());
}
@Test
public void testDuplicateHandlerRegistrations() throws Exception {
String url = "http://type1handler:8080";
serviceRegistry.registerHost(url, "127.0.0.1", 1024, 1, 1);
String receiptType = "type1";
// we should start with no handlers
List<ServiceRegistration> hosts = serviceRegistry.getServiceRegistrationsByLoad(receiptType);
assertEquals(0, hosts.size());
// register a handler
serviceRegistry.registerService(receiptType, url, PATH);
hosts = serviceRegistry.getServiceRegistrationsByLoad("type1");
assertEquals(1, hosts.size());
assertEquals(url, hosts.get(0).getHost());
// set the host to be in maintenance mode
serviceRegistry.setMaintenanceStatus(url, true);
hosts = serviceRegistry.getServiceRegistrationsByLoad("type1");
assertEquals(0, hosts.size());
// re-register the host. this should not unset the maintenance mode and should not throw an exception
serviceRegistry.unregisterHost(url);
serviceRegistry.registerHost(url, "127.0.0.1", 1024, 1, 1);
serviceRegistry.registerService(receiptType, url, PATH);
// zero because it's still in maintenance mode
assertEquals(0, serviceRegistry.getServiceRegistrationsByLoad(receiptType).size());
// unregister
serviceRegistry.unRegisterService(receiptType, url);
hosts = serviceRegistry.getServiceRegistrationsByLoad("type1");
assertEquals(0, hosts.size());
}
@Test
public void testMarshallingWithJsonPayload() throws Exception {
final String payload = "{'foo' : 'bar'}";
Job job = new JobImpl();
job.setPayload(payload);
String marshalledJob = JobParser.toXml(new JaxbJob(job));
Job unmarshalledJob = JobParser.parseJob(marshalledJob);
assertEquals("json from unmarshalled job should remain unchanged", StringUtils.trim(payload),
StringUtils.trim(unmarshalledJob.getPayload()));
}
@Test
public void testMarshallingWithXmlPayload() throws Exception {
final String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<random xmlns:ns2=\"http://mediapackage.opencastproject.org\" xmlns:ns3=\"http://job.opencastproject.org/\">something</random>";
Job job = new JobImpl();
job.setPayload(payload);
String marshalledJob = JobParser.toXml(new JaxbJob(job));
Job unmarshalledJob = JobParser.parseJob(marshalledJob);
assertEquals("xml from unmarshalled job should remain unchanged", StringUtils.trim(payload),
StringUtils.trim(unmarshalledJob.getPayload()));
}
@Test
public void testGetArguments() throws Exception {
String arg1 = "arg1";
String arg2 = "<some>xml</some>";
Job job = serviceRegistry.createJob(JOB_TYPE_1, "some_operation", Arrays.asList(arg1, arg2));
Job jobFromDb = serviceRegistry.getJob(job.getId());
Assert.assertNotNull("No arguments persisted in job", jobFromDb.getArguments());
assertEquals("Wrong number of arguments persisted", 2, jobFromDb.getArguments().size());
assertEquals("Arguments not persisted in order", arg1, jobFromDb.getArguments().get(0));
assertEquals("Arguments not persisted in order", arg2, jobFromDb.getArguments().get(1));
}
@Test
public void testVersionIncrements() throws Exception {
Job job = serviceRegistry.createJob(JOB_TYPE_1, "some_operation", null, null, false);
assertEquals("Newly created jobs should have a version of 1", 1, job.getVersion());
job = serviceRegistry.getJob(job.getId());
job.setPayload("update1");
job = serviceRegistry.updateJob(job);
job = serviceRegistry.getJob(job.getId());
assertEquals("Updated job should have a version of 2", 2, job.getVersion());
job = serviceRegistry.getJob(job.getId());
job.setPayload("update2");
job = serviceRegistry.updateJob(job);
job = serviceRegistry.getJob(job.getId());
assertEquals("Updated job should have a version of 3", 3, job.getVersion());
}
@Test
public void testOptimisticLocking() throws Exception {
// Disable job dispatching by setting both hosts to be in maintenance mode
serviceRegistry.setMaintenanceStatus(LOCALHOST, true);
serviceRegistry.setMaintenanceStatus(REMOTEHOST, true);
// Create a job
String arg1 = "arg1";
String arg2 = "<some>xml</some>";
Job job = serviceRegistry.createJob(JOB_TYPE_1, "some_operation", Arrays.asList(arg1, arg2), null, false);
// Grab another reference to this job
Job jobFromDb = serviceRegistry.getJob(job.getId());
// Modify the job and save it
job.setPayload("something produced by this client");
job = serviceRegistry.updateJob(job);
job = serviceRegistry.getJob(job.getId());
// Ensure that the job version is higher than the snapshot we loaded from the database
assertTrue("Version not incremented", job.getVersion() > jobFromDb.getVersion());
// Try to modify and save the outdated reference
try {
jobFromDb = serviceRegistry.updateJob(jobFromDb);
Assert.fail();
} catch (Exception e) {
// do nothinng
}
}
@Test
public void testJobsQueuedOnServiceUnregistration() throws Exception {
// Create a job
Job job = serviceRegistry.createJob(JOB_TYPE_1, "some operation", null, null, false, 1.0f);
// Set its status to running on a localhost
job.setStatus(Status.RUNNING);
job.setDispatchable(true);
job.setJobType(regType1Localhost.getServiceType());
job.setProcessingHost(regType1Localhost.getHost());
job = serviceRegistry.updateJob(job);
// Ensure that we get the job back from the service in its running state
assertEquals("Job should be running", Status.RUNNING, serviceRegistry.getJob(job.getId()).getStatus());
// Now unregister regType1Host1, and the job should go back to queued
serviceRegistry.unRegisterService(regType1Localhost.getServiceType(), regType1Localhost.getHost());
// Ensure that the job is queued now
assertEquals("Job should be queued", Status.RESTART, serviceRegistry.getJob(job.getId()).getStatus());
Assert.assertNull("Job's processing service should be null", serviceRegistry.getJob(job.getId())
.getProcessingHost());
}
@Test
public void testMaxLoad() throws Exception {
assertEquals(1.0f, serviceRegistry.getMaxLoads().get(serviceRegistry.getRegistryHostname()).getLoadFactor(), 0.01f);
assertEquals(1.0f, serviceRegistry.getMaxLoads().get(LOCALHOST).getLoadFactor(), 0.01f);
assertEquals(1.0f, serviceRegistry.getMaxLoads().get(REMOTEHOST).getLoadFactor(), 0.01f);
assertEquals(1.0f, serviceRegistry.getMaxLoadOnNode(serviceRegistry.getRegistryHostname()).getLoadFactor(), 0.01f);
}
@Test
public void testServiceUnregistration() throws Exception {
// Create a job
Job job = serviceRegistry.createJob(JOB_TYPE_1, "some operation", null, null, false);
// Set its status to running on a localhost
job.setStatus(Status.RUNNING);
job.setDispatchable(true);
job.setJobType(regType1Localhost.getServiceType());
job.setProcessingHost(regType1Localhost.getHost());
job = serviceRegistry.updateJob(job);
// Unregister the service
serviceRegistry.unRegisterService(JOB_TYPE_1, LOCALHOST);
// Ensure that the job is once again queued, so it can be dispatched to a server ready to accept it
assertEquals("Job should be queued", Status.RESTART, serviceRegistry.getJob(job.getId()).getStatus());
Assert.assertNull("Job should have no associated processor", serviceRegistry.getJob(job.getId())
.getProcessingHost());
}
@Test
public void testHostUnregistration() throws Exception {
// Create a job
Job job = serviceRegistry.createJob(JOB_TYPE_1, "some operation", null, null, false);
// Set its status to running on a localhost
job.setStatus(Status.RUNNING);
job.setDispatchable(true);
job.setJobType(regType1Localhost.getServiceType());
job.setProcessingHost(regType1Localhost.getHost());
job = serviceRegistry.updateJob(job);
// Unregister the host that's running the service responsible for this job
serviceRegistry.unregisterHost(LOCALHOST);
// Ensure that the job is once again queued, so it can be dispatched to a server ready to accept it
assertEquals("Job should be queued", Status.RESTART, serviceRegistry.getJob(job.getId()).getStatus());
Assert.assertNull("Job should have no associated processor", serviceRegistry.getJob(job.getId())
.getProcessingHost());
}
@Test
public void testRemoveJobsWithoutParent() throws Exception {
Job jobRunning = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false, 1.0f);
jobRunning.setStatus(Status.RUNNING);
jobRunning = serviceRegistry.updateJob(jobRunning);
Job jobFinished = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false, 1.0f);
jobFinished.setStatus(Status.FINISHED);
jobFinished = serviceRegistry.updateJob(jobFinished);
Job jobFailed = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false, 1.0f);
jobFailed.setStatus(Status.FAILED, FailureReason.NONE);
jobFailed = serviceRegistry.updateJob(jobFailed);
Job parent = serviceRegistry.createJob(JOB_TYPE_1, "START_OPERATION", null, null, false, 1.0f);
parent.setStatus(Status.FAILED);
parent = serviceRegistry.updateJob(parent);
Job jobWithParent = serviceRegistry.createJob(JOB_TYPE_1, OPERATION_NAME, null, null, false, parent);
jobWithParent.setStatus(Status.FAILED);
jobWithParent = serviceRegistry.updateJob(jobWithParent);
List<Job> jobs = serviceRegistry.getJobs(null, null);
assertEquals(5, jobs.size());
serviceRegistry.removeParentlessJobs(0);
jobs = serviceRegistry.getJobs(null, null);
assertEquals(3, jobs.size());
jobRunning = serviceRegistry.getJob(jobRunning.getId());
jobRunning.setStatus(Status.FINISHED);
jobRunning = serviceRegistry.updateJob(jobRunning);
serviceRegistry.removeParentlessJobs(0);
jobs = serviceRegistry.getJobs(null, null);
assertEquals(2, jobs.size());
}
}