@Test
  public void testGetJobSummaryWithoutNextRun() throws Exception {
    // 31st of February, there is no such day.
    String cronSchedule = "* * 31 2 *";

    TaskConfig task =
        nonProductionTask()
            .setJobName(JOB_KEY.getName())
            .setOwner(ROLE_IDENTITY)
            .setEnvironment(JOB_KEY.getEnvironment());
    JobConfiguration job = makeJob().setCronSchedule(cronSchedule).setTaskConfig(task);
    expect(cronPredictor.predictNextRun(CrontabEntry.parse(cronSchedule)))
        .andReturn(Optional.absent())
        .anyTimes();
    storageUtil.expectTaskFetch(Query.roleScoped(ROLE));
    Set<JobConfiguration> jobOnly = ImmutableSet.of(job);
    expect(storageUtil.jobStore.fetchJobs()).andReturn(IJobConfiguration.setFromBuilders(jobOnly));

    control.replay();

    JobSummaryResult result = thrift.getJobSummary(ROLE).getResult().getJobSummaryResult();
    assertEquals(1, result.getSummaries().size());
    assertFalse(result.getSummariesIterator().next().isSetNextCronRunMs());
  }
  @Test
  public void testGetJobSummary() throws Exception {
    long nextCronRunMs = 100;
    TaskConfig ownedCronJobTask =
        nonProductionTask()
            .setJob(JOB_KEY.newBuilder())
            .setJobName(JOB_KEY.getName())
            .setOwner(ROLE_IDENTITY)
            .setEnvironment(JOB_KEY.getEnvironment());
    JobConfiguration ownedCronJob =
        makeJob().setCronSchedule(CRON_SCHEDULE).setTaskConfig(ownedCronJobTask);
    IScheduledTask ownedCronJobScheduledTask =
        IScheduledTask.build(
            new ScheduledTask()
                .setAssignedTask(new AssignedTask().setTask(ownedCronJobTask))
                .setStatus(ScheduleStatus.ASSIGNED));
    Identity otherOwner = new Identity("other", "other");
    JobConfiguration unownedCronJob =
        makeJob()
            .setOwner(otherOwner)
            .setCronSchedule(CRON_SCHEDULE)
            .setKey(JOB_KEY.newBuilder().setRole("other"))
            .setTaskConfig(ownedCronJobTask.deepCopy().setOwner(otherOwner));
    TaskConfig ownedImmediateTaskInfo =
        defaultTask(false)
            .setJob(JOB_KEY.newBuilder().setName("immediate"))
            .setJobName("immediate")
            .setOwner(ROLE_IDENTITY);
    Set<JobConfiguration> ownedCronJobOnly = ImmutableSet.of(ownedCronJob);
    Set<JobSummary> ownedCronJobSummaryOnly =
        ImmutableSet.of(
            new JobSummary()
                .setJob(ownedCronJob)
                .setStats(new JobStats())
                .setNextCronRunMs(nextCronRunMs));
    Set<JobSummary> ownedCronJobSummaryWithRunningTask =
        ImmutableSet.of(
            new JobSummary()
                .setJob(ownedCronJob)
                .setStats(new JobStats().setActiveTaskCount(1))
                .setNextCronRunMs(nextCronRunMs));
    Set<JobConfiguration> unownedCronJobOnly = ImmutableSet.of(unownedCronJob);
    Set<JobConfiguration> bothCronJobs = ImmutableSet.of(ownedCronJob, unownedCronJob);

    IScheduledTask ownedImmediateTask =
        IScheduledTask.build(
            new ScheduledTask()
                .setAssignedTask(new AssignedTask().setTask(ownedImmediateTaskInfo))
                .setStatus(ScheduleStatus.ASSIGNED));
    JobConfiguration ownedImmediateJob =
        new JobConfiguration()
            .setKey(JOB_KEY.newBuilder().setName("immediate"))
            .setOwner(ROLE_IDENTITY)
            .setInstanceCount(1)
            .setTaskConfig(ownedImmediateTaskInfo);
    Builder query = Query.roleScoped(ROLE);

    Set<JobSummary> ownedImmediateJobSummaryOnly =
        ImmutableSet.of(
            new JobSummary()
                .setJob(ownedImmediateJob)
                .setStats(new JobStats().setActiveTaskCount(1)));

    expect(cronPredictor.predictNextRun(CrontabEntry.parse(CRON_SCHEDULE)))
        .andReturn(Optional.of(new Date(nextCronRunMs)))
        .anyTimes();

    storageUtil.expectTaskFetch(query);
    expect(storageUtil.jobStore.fetchJobs())
        .andReturn(IJobConfiguration.setFromBuilders(ownedCronJobOnly));

    storageUtil.expectTaskFetch(query);
    expect(storageUtil.jobStore.fetchJobs())
        .andReturn(IJobConfiguration.setFromBuilders(bothCronJobs));

    storageUtil.expectTaskFetch(query, ownedImmediateTask);
    expect(storageUtil.jobStore.fetchJobs())
        .andReturn(IJobConfiguration.setFromBuilders(unownedCronJobOnly));

    storageUtil.expectTaskFetch(query);
    expect(storageUtil.jobStore.fetchJobs()).andReturn(ImmutableSet.of());

    // Handle the case where a cron job has a running task (same JobKey present in both stores).
    storageUtil.expectTaskFetch(query, ownedCronJobScheduledTask);
    expect(storageUtil.jobStore.fetchJobs())
        .andReturn(IJobConfiguration.setFromBuilders(ImmutableSet.of(ownedCronJob)));

    control.replay();

    assertEquals(jobSummaryResponse(ownedCronJobSummaryOnly), thrift.getJobSummary(ROLE));

    assertEquals(jobSummaryResponse(ownedCronJobSummaryOnly), thrift.getJobSummary(ROLE));

    Response jobSummaryResponse = thrift.getJobSummary(ROLE);
    assertEquals(
        jobSummaryResponse(ownedImmediateJobSummaryOnly),
        IResponse.build(jobSummaryResponse).newBuilder());

    assertEquals(jobSummaryResponse(ImmutableSet.of()), thrift.getJobSummary(ROLE));

    assertEquals(
        jobSummaryResponse(ownedCronJobSummaryWithRunningTask), thrift.getJobSummary(ROLE));
  }