/*
* Copyright 2007 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.server.itests.procs;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.util.UUID;
import junit.framework.TestCase;
import ome.api.IQuery;
import ome.api.JobHandle;
import ome.conditions.SecurityViolation;
import ome.model.jobs.Job;
import ome.model.jobs.JobStatus;
import ome.model.jobs.ScriptJob;
import ome.security.SecuritySystem;
import ome.server.itests.ManagedContextFixture;
import ome.services.JobBean;
import ome.services.procs.ProcessManager;
import ome.services.procs.ProcessorSkeleton;
import ome.services.sessions.SessionManager;
import ome.services.util.Executor;
import ome.system.Principal;
import ome.system.ServiceFactory;
import ome.util.ContextFilter;
import omero.ApiUsageException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.springframework.transaction.annotation.Transactional;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* @author Josh Moore, josh at glencoesoftware.com
* @since 3.0-Beta3
*/
@Test(groups = { "jobs", "integration", "broken" })
public class JobHandleTest extends TestCase {
protected ManagedContextFixture fixture;
protected long id;
protected JobHandle jh;
protected PManager mgr;
@Override
@BeforeMethod
protected void setUp() throws Exception {
super.setUp();
fixture = new ManagedContextFixture();
mgr = new PManager(new P(fixture.internalSf.getQueryService()),
fixture.mgr, fixture.security, fixture.ex);
JobBean bean = (JobBean) fixture.ctx
.getBean("internal-ome.api.JobHandle");
Field pm = bean.getClass().getDeclaredField("pm");
pm.setAccessible(true);
pm.set(bean, mgr);
// Fixing notifications
Scheduler sched = (Scheduler) fixture.ctx.getBean("scheduler");
JobDetail manual = (JobDetail) fixture.ctx.getBean("process-jobs-run");
manual.getJobDataMap().put("processManager", mgr);
sched.addJob(manual, true);
}
@Override
@AfterMethod
protected void tearDown() throws Exception {
super.tearDown();
}
@Test
public void testJobIsSavedToDatabase() throws Exception {
ScriptJob job = new ScriptJob();
String uuid = UUID.randomUUID().toString();
job.setMessage(uuid);
jh = fixture.managedSf.createJobHandle();
id = jh.submit(job);
assertTrue(id > 0L);
}
@Test(expectedExceptions = SecurityViolation.class)
public void testJobCannotBeCreatedViaIUpdate() throws Exception {
ScriptJob job = new ScriptJob();
job.setSubmitted(new Timestamp(System.currentTimeMillis()));
job.setType("user");
job.setGroupname("default");
job.setMessage("test of override via iupdate");
job.setStatus(new JobStatus("Submitted"));
job.setUsername("root");
job.setScheduledFor(new Timestamp(System.currentTimeMillis() + 100L));
fixture.managedSf.getUpdateService().saveObject(job);
}
@Test
public void testUserCanReattach() throws Exception {
testJobIsSavedToDatabase();
JobHandle attach = fixture.managedSf.createJobHandle();
JobStatus status = attach.attach(id);
assertTrue(status != null && status.getValue() != null);
}
@Test
public void testUserCanRetrieveJob() throws Exception {
testJobIsSavedToDatabase();
Job job = jh.getJob();
assertTrue(job != null && job.isLoaded());
}
@Test
public void testMultipleUsersCanAttach() throws Exception {
testJobIsSavedToDatabase();
JobHandle attach1 = fixture.managedSf.createJobHandle();
JobHandle attach2 = fixture.managedSf.createJobHandle();
String user1 = fixture.getCurrentUser();
String user2 = fixture.newUser();
attach1.attach(id);
fixture.setCurrentUser(user2);
attach2.attach(id);
attach2.cancelJob();
fixture.setCurrentUser(user1);
JobStatus cancelled = attach1.jobStatus();
assertEquals(JobHandle.CANCELLED, cancelled.getValue());
}
@Test
public void testProcessManagerIsNotified() throws Exception {
testJobIsSavedToDatabase();
Thread.sleep(1000L);
assertTrue(mgr.called);
}
@Test
public void testJobSwitchedToWaitingIfNoProcessorTakesIt() throws Exception {
testJobIsSavedToDatabase();
mgr.run();
assertEquals(JobHandle.WAITING, jh.jobStatus().getValue());
}
@Test
public void testPassiviationWorksProperly() throws Exception {
fail("NYI");
}
@Test
public void testCancelJobWorks() throws Exception {
fail("NYI");
}
@Test
public void testProcessCancelsJobWorks() throws Exception {
fail("NYI");
}
@Test
public void testServiceNotifiedOfServiceCompletionByProcess()
throws Exception {
fail("NYI");
}
@Test
public void testUserForgetsToUploadScript() throws Exception {
fail("NYI");
}
@Test
public void testCheckAndRegisterNoticesFinishedProcesses() throws Exception {
fail("NYI");
}
@Test
public void testJobRetrievalCanBeSpecifiedViaQuery() throws Exception {
fail("NYI");
// Job job = iQuery.findByQuery("job.query."+job.getClass(),idParams);
}
@Test
public void testWalkingThroughReturnedJob() throws Exception {
testJobIsSavedToDatabase();
Job job = jh.getJob();
job.acceptFilter(new ContextFilter() {
});
}
/**
* Reproduces use of jobs as seen in SharedResources.acquireProcessor()
* @throws Exception
*/
@Test(groups = "ticket:3929")
public void testProcessorJobsDirect() throws Exception {
JobHandle handle = fixture.managedSf.createJobHandle();
Job job = new ScriptJob();
JobStatus status = new JobStatus();
status.setValue(JobHandle.WAITING);
job.setStatus(status);
id = handle.submit(job);
handle.close();
handle = fixture.managedSf.createJobHandle();
handle.attach(id);
handle.setStatusAndMessage(JobHandle.RUNNING, "ha!");
handle.close();
}
/**
* Reproduces use of jobs as seen in SharedResources.acquireProcessor()
* copying the methods themselves
* @throws Exception
*/
@Test(groups = "ticket:3929")
public void testProcessorJobsViaMethods() throws Exception {
Job job = new ScriptJob();
JobStatus status = new JobStatus();
status.setValue(JobHandle.WAITING);
job = saveJob(fixture.ex, fixture.getPrincipal(), job);
updateJob(fixture.ex, fixture.getPrincipal(), job.getId(),
JobHandle.ERROR, "No processor");
}
private ome.model.jobs.Job saveJob(Executor ex, Principal p,
final Job job) {
// First create the job with a status of WAITING.
// The InteractiveProcessor will be responsible for its
// further lifetime.
final ome.model.jobs.Job savedJob = (ome.model.jobs.Job) ex.execute(p,
new Executor.SimpleWork(this, "submitJob") {
@Transactional(readOnly = false)
public ome.model.jobs.Job doWork(Session session,
ServiceFactory sf) {
final JobHandle handle = sf.createJobHandle();
try {
handle.submit(job);
return handle.getJob();
} catch (ome.conditions.ApiUsageException e) {
return null;
} catch (ObjectNotFoundException onfe) {
return null;
} finally {
if (handle != null) {
handle.close();
}
}
}
});
return savedJob;
}
private void updateJob(Executor ex, Principal p, final long id,
final String status, final String message) {
ex.execute(p, new Executor.SimpleWork(this, "updateJob") {
@Transactional(readOnly = false)
public Object doWork(Session session, ServiceFactory sf) {
final JobHandle handle = sf.createJobHandle();
try {
handle.attach(id);
handle.setStatusAndMessage(status, message);
return null;
} finally {
handle.close();
}
}
});
}
}
class P extends ProcessorSkeleton {
public P(IQuery query) {
this.setQueryService(query);
}
}
class PManager extends ProcessManager {
public PManager(P p, SessionManager mgr, SecuritySystem sec, Executor ex) {
super(mgr, sec, ex, p);
if (sec == null || ex == null) {
throw new RuntimeException("Null argument");
}
}
public volatile boolean called = false;
@Override
public void doRun() {
called = true;
super.doRun();
}
public void waitFor(long timeout) {
long stop = System.currentTimeMillis() + timeout;
while (System.currentTimeMillis() < stop) {
try {
Thread.sleep(500L);
} catch (InterruptedException ie) {
// ok
}
}
}
}