Repository: aurora
Updated Branches:
  refs/heads/master 80139da46 -> 284f40f5e


http://git-wip-us.apache.org/repos/asf/aurora/blob/284f40f5/src/test/java/org/apache/aurora/scheduler/storage/AbstractJobUpdateStoreTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/storage/AbstractJobUpdateStoreTest.java
 
b/src/test/java/org/apache/aurora/scheduler/storage/AbstractJobUpdateStoreTest.java
index 9fab7ae..1510817 100644
--- 
a/src/test/java/org/apache/aurora/scheduler/storage/AbstractJobUpdateStoreTest.java
+++ 
b/src/test/java/org/apache/aurora/scheduler/storage/AbstractJobUpdateStoreTest.java
@@ -15,16 +15,13 @@
 package org.apache.aurora.scheduler.storage;
 
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import com.google.inject.Injector;
 
 import org.apache.aurora.gen.InstanceTaskConfig;
@@ -46,48 +43,37 @@ import org.apache.aurora.gen.TaskConfig;
 import org.apache.aurora.scheduler.base.JobKeys;
 import org.apache.aurora.scheduler.base.TaskTestUtil;
 import org.apache.aurora.scheduler.storage.Storage.MutateWork.NoResult;
-import org.apache.aurora.scheduler.storage.Storage.StorageException;
 import org.apache.aurora.scheduler.storage.entities.IJobInstanceUpdateEvent;
 import org.apache.aurora.scheduler.storage.entities.IJobKey;
-import org.apache.aurora.scheduler.storage.entities.IJobUpdate;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateDetails;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateEvent;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateInstructions;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateKey;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateQuery;
-import org.apache.aurora.scheduler.storage.entities.IJobUpdateState;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateSummary;
 import org.apache.aurora.scheduler.storage.testing.StorageEntityUtil;
-import org.apache.aurora.scheduler.testing.FakeStatsProvider;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.apache.aurora.gen.JobUpdateAction.INSTANCE_ROLLBACK_FAILED;
 import static org.apache.aurora.gen.JobUpdateAction.INSTANCE_ROLLED_BACK;
 import static org.apache.aurora.gen.JobUpdateAction.INSTANCE_ROLLING_BACK;
 import static org.apache.aurora.gen.JobUpdateAction.INSTANCE_UPDATED;
 import static org.apache.aurora.gen.JobUpdateAction.INSTANCE_UPDATING;
 import static org.apache.aurora.gen.JobUpdateStatus.ABORTED;
 import static org.apache.aurora.gen.JobUpdateStatus.ERROR;
-import static org.apache.aurora.gen.JobUpdateStatus.FAILED;
 import static org.apache.aurora.gen.JobUpdateStatus.ROLLED_BACK;
 import static org.apache.aurora.gen.JobUpdateStatus.ROLLING_BACK;
 import static org.apache.aurora.gen.JobUpdateStatus.ROLLING_FORWARD;
-import static org.apache.aurora.gen.JobUpdateStatus.ROLL_BACK_PAUSED;
 import static org.apache.aurora.gen.JobUpdateStatus.ROLL_FORWARD_PAUSED;
 import static org.apache.aurora.gen.Resource.diskMb;
 import static org.apache.aurora.gen.Resource.numCpus;
 import static org.apache.aurora.gen.Resource.ramMb;
-import static org.apache.aurora.scheduler.storage.Util.jobUpdateActionStatName;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 
 public abstract class AbstractJobUpdateStoreTest {
 
   private static final IJobKey JOB = JobKeys.from("testRole", "testEnv", 
"job");
-  private static final IJobUpdateKey UPDATE1 =
-      IJobUpdateKey.build(new JobUpdateKey(JOB.newBuilder(), "update1"));
   private static final long CREATED_MS = 111L;
   private static final IJobUpdateEvent FIRST_EVENT =
       makeJobUpdateEvent(ROLLING_FORWARD, CREATED_MS);
@@ -95,13 +81,11 @@ public abstract class AbstractJobUpdateStoreTest {
       ImmutableSet.of(new Metadata("k1", "v1"), new Metadata("k2", "v2"), new 
Metadata("k3", "v3"));
 
   private Storage storage;
-  private FakeStatsProvider stats;
 
   @Before
   public void setUp() throws Exception {
     Injector injector = createStorageInjector();
     storage = injector.getInstance(Storage.class);
-    stats = injector.getInstance(FakeStatsProvider.class);
   }
 
   protected abstract Injector createStorageInjector();
@@ -111,9 +95,18 @@ public abstract class AbstractJobUpdateStoreTest {
     truncateUpdates();
   }
 
-  private static IJobUpdate makeFullyPopulatedUpdate(IJobUpdateKey key) {
-    JobUpdate builder = makeJobUpdate(key).newBuilder();
-    JobUpdateInstructions instructions = builder.getInstructions();
+  private static IJobUpdateDetails makeFullyPopulatedUpdate(IJobUpdateKey key) 
{
+    JobUpdateDetails builder = makeJobUpdate(key).newBuilder()
+        .setUpdateEvents(ImmutableList.of(new JobUpdateEvent()
+            .setStatus(ROLLING_FORWARD)
+            .setTimestampMs(1)
+            .setUser("user")
+            .setMessage("message")))
+        .setInstanceEvents(ImmutableList.of(new JobInstanceUpdateEvent()
+            .setTimestampMs(2)
+            .setInstanceId(1)
+            .setAction(INSTANCE_UPDATING)));
+    JobUpdateInstructions instructions = builder.getUpdate().getInstructions();
     Stream.of(
         instructions.getInitialState().stream()
             .map(InstanceTaskConfig::getInstances)
@@ -130,7 +123,7 @@ public abstract class AbstractJobUpdateStoreTest {
             range.setLast(1);
           }
         });
-    return IJobUpdate.build(builder);
+    return IJobUpdateDetails.build(builder);
   }
 
   @Test
@@ -138,8 +131,8 @@ public abstract class AbstractJobUpdateStoreTest {
     IJobUpdateKey updateId1 = makeKey(JobKeys.from("role", "env", "name1"), 
"u1");
     IJobUpdateKey updateId2 = makeKey(JobKeys.from("role", "env", "name2"), 
"u2");
 
-    IJobUpdate update1 = makeFullyPopulatedUpdate(updateId1);
-    IJobUpdate update2 = makeJobUpdate(updateId2);
+    IJobUpdateDetails update1 = makeFullyPopulatedUpdate(updateId1);
+    IJobUpdateDetails update2 = makeJobUpdate(updateId2);
 
     assertEquals(Optional.absent(), getUpdate(updateId1));
     assertEquals(Optional.absent(), getUpdate(updateId2));
@@ -151,19 +144,10 @@ public abstract class AbstractJobUpdateStoreTest {
         StorageEntityUtil.getField(Range.class, "first"),
         StorageEntityUtil.getField(Range.class, "last"));
     saveUpdate(update1);
-    assertUpdate(update1);
+    assertEquals(withUpdateState(update1, ROLLING_FORWARD, 1, 2), 
getUpdate(key(update1)).get());
 
     saveUpdate(update2);
     assertUpdate(update2);
-
-    // Colliding update keys should be forbidden.
-    IJobUpdate update3 = makeJobUpdate(updateId2);
-    try {
-      saveUpdate(update3);
-      fail("Update ID collision should not be allowed");
-    } catch (StorageException e) {
-      // Expected.
-    }
   }
 
   @Test
@@ -171,17 +155,14 @@ public abstract class AbstractJobUpdateStoreTest {
     // AURORA-1494 regression test validating max resources values are allowed.
     IJobUpdateKey updateId = makeKey(JobKeys.from("role", "env", "name1"), 
"u1");
 
-    JobUpdate builder = makeFullyPopulatedUpdate(updateId).newBuilder();
-    builder.getInstructions().getDesiredState().getTask().setResources(
+    JobUpdateDetails builder = makeFullyPopulatedUpdate(updateId).newBuilder();
+    
builder.getUpdate().getInstructions().getDesiredState().getTask().setResources(
             ImmutableSet.of(
                     numCpus(Double.MAX_VALUE),
                     ramMb(Long.MAX_VALUE),
                     diskMb(Long.MAX_VALUE)));
 
-    IJobUpdate update = IJobUpdate.build(builder);
-
-    assertEquals(Optional.absent(), getUpdate(updateId));
-
+    IJobUpdateDetails update = makeFullyPopulatedUpdate(updateId);
     StorageEntityUtil.assertFullyPopulated(
         update,
         StorageEntityUtil.getField(JobUpdateSummary.class, "state"),
@@ -189,86 +170,86 @@ public abstract class AbstractJobUpdateStoreTest {
         StorageEntityUtil.getField(Range.class, "first"),
         StorageEntityUtil.getField(Range.class, "last"));
     saveUpdate(update);
-    assertUpdate(update);
+    assertEquals(withUpdateState(update, ROLLING_FORWARD, 1, 2), 
getUpdate(key(update)).get());
   }
 
   @Test
   public void testSaveNullInitialState() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    builder.getInstructions().unsetInitialState();
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    builder.getUpdate().getInstructions().unsetInitialState();
 
     // Save with null initial state instances.
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
 
-    builder.getInstructions().setInitialState(ImmutableSet.of());
-    assertUpdate(IJobUpdate.build(builder));
+    builder.getUpdate().getInstructions().setInitialState(ImmutableSet.of());
+    assertUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test
   public void testSaveNullDesiredState() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    builder.getInstructions().unsetDesiredState();
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    builder.getUpdate().getInstructions().unsetDesiredState();
 
     // Save with null desired state instances.
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
 
-    assertUpdate(IJobUpdate.build(builder));
+    assertUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test(expected = IllegalArgumentException.class)
   public void testSaveBothInitialAndDesiredMissingThrows() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    builder.getInstructions().unsetInitialState();
-    builder.getInstructions().unsetDesiredState();
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    builder.getUpdate().getInstructions().unsetInitialState();
+    builder.getUpdate().getInstructions().unsetDesiredState();
 
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test(expected = NullPointerException.class)
   public void testSaveNullInitialStateTaskThrows() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    builder.getInstructions().getInitialState().add(
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    builder.getUpdate().getInstructions().getInitialState().add(
         new InstanceTaskConfig(null, ImmutableSet.of()));
 
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test(expected = IllegalArgumentException.class)
   public void testSaveEmptyInitialStateRangesThrows() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    builder.getInstructions().getInitialState().add(
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    builder.getUpdate().getInstructions().getInitialState().add(
         new InstanceTaskConfig(
             TaskTestUtil.makeConfig(TaskTestUtil.JOB).newBuilder(),
             ImmutableSet.of()));
 
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test(expected = NullPointerException.class)
   public void testSaveNullDesiredStateTaskThrows() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    builder.getInstructions().getDesiredState().setTask(null);
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    builder.getUpdate().getInstructions().getDesiredState().setTask(null);
 
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test(expected = IllegalArgumentException.class)
   public void testSaveEmptyDesiredStateRangesThrows() {
-    JobUpdate builder = makeJobUpdate(makeKey("u1")).newBuilder();
-    
builder.getInstructions().getDesiredState().setInstances(ImmutableSet.of());
+    JobUpdateDetails builder = makeJobUpdate(makeKey("u1")).newBuilder();
+    
builder.getUpdate().getInstructions().getDesiredState().setInstances(ImmutableSet.of());
 
-    saveUpdate(IJobUpdate.build(builder));
+    saveUpdate(IJobUpdateDetails.build(builder));
   }
 
   @Test
   public void testSaveJobUpdateEmptyInstanceOverrides() {
     IJobUpdateKey updateId = makeKey("u1");
 
-    IJobUpdate update = makeJobUpdate(updateId);
-    JobUpdate builder = update.newBuilder();
-    
builder.getInstructions().getSettings().setUpdateOnlyTheseInstances(ImmutableSet.of());
+    JobUpdateDetails builder = makeJobUpdate(updateId).newBuilder();
+    builder.getUpdate().getInstructions().getSettings()
+        .setUpdateOnlyTheseInstances(ImmutableSet.of());
 
-    IJobUpdate expected = IJobUpdate.build(builder);
+    IJobUpdateDetails expected = IJobUpdateDetails.build(builder);
 
     // Save with empty overrides.
     saveUpdate(expected);
@@ -279,126 +260,42 @@ public abstract class AbstractJobUpdateStoreTest {
   public void testSaveJobUpdateNullInstanceOverrides() {
     IJobUpdateKey updateId = makeKey("u1");
 
-    IJobUpdate update = makeJobUpdate(updateId);
-    JobUpdate builder = update.newBuilder();
-    
builder.getInstructions().getSettings().setUpdateOnlyTheseInstances(ImmutableSet.of());
+    JobUpdateDetails builder = makeJobUpdate(updateId).newBuilder();
+    builder.getUpdate().getInstructions().getSettings()
+        .setUpdateOnlyTheseInstances(ImmutableSet.of());
 
-    IJobUpdate expected = IJobUpdate.build(builder);
+    IJobUpdateDetails expected = IJobUpdateDetails.build(builder);
 
     // Save with null overrides.
-    builder.getInstructions().getSettings().setUpdateOnlyTheseInstances(null);
-    saveUpdate(IJobUpdate.build(builder));
+    
builder.getUpdate().getInstructions().getSettings().setUpdateOnlyTheseInstances(null);
+    saveUpdate(IJobUpdateDetails.build(builder));
     assertUpdate(expected);
   }
 
-  @Test(expected = StorageException.class)
-  public void testSaveJobUpdateTwiceThrows() {
-    IJobUpdateKey updateId = makeKey("u1");
-    IJobUpdate update = makeJobUpdate(updateId);
-
-    saveUpdate(update);
-    saveUpdate(update);
-  }
-
-  @Test
-  public void testSaveJobEvents() {
-    IJobUpdateKey updateId = makeKey("u3");
-    IJobUpdate update = makeJobUpdate(updateId);
-    IJobUpdateEvent event1 = makeJobUpdateEvent(ROLLING_FORWARD, 124L);
-    IJobUpdateEvent event2 = makeJobUpdateEvent(ROLL_FORWARD_PAUSED, 125L);
-
-    saveUpdate(update);
-    assertUpdate(update);
-    assertEquals(ImmutableList.of(FIRST_EVENT), 
getUpdateDetails(updateId).get().getUpdateEvents());
-
-    saveJobEvent(event1, updateId);
-    assertEquals(
-        populateExpected(update, ROLLING_FORWARD, CREATED_MS, 124L),
-        getUpdateDetails(updateId).get().getUpdate());
-    assertEquals(event1, 
getUpdateDetails(updateId).get().getUpdateEvents().get(1));
-
-    saveJobEvent(event2, updateId);
-    assertEquals(
-        populateExpected(update, ROLL_FORWARD_PAUSED, CREATED_MS, 125L),
-        getUpdateDetails(updateId).get().getUpdate());
-    assertEquals(event1, 
getUpdateDetails(updateId).get().getUpdateEvents().get(1));
-    assertEquals(event2, 
getUpdateDetails(updateId).get().getUpdateEvents().get(2));
-    assertStats(ImmutableMap.of(ROLL_FORWARD_PAUSED, 1, ROLLING_FORWARD, 2));
-  }
-
-  private <T extends Number> void assertStats(Map<JobUpdateStatus, T> 
expected) {
-    for (Map.Entry<JobUpdateStatus, T> entry : expected.entrySet()) {
-      assertEquals(
-          entry.getValue().longValue(),
-          stats.getLongValue(Util.jobUpdateStatusStatName(entry.getKey())));
-    }
-  }
-
-  @Test
-  public void testSaveInstanceEvents() {
-    IJobUpdateKey updateId = makeKey("u3");
-    IJobUpdate update = makeJobUpdate(updateId);
-    IJobInstanceUpdateEvent event1 = makeJobInstanceEvent(0, 125L, 
INSTANCE_UPDATED);
-    IJobInstanceUpdateEvent event2 = makeJobInstanceEvent(1, 126L, 
INSTANCE_ROLLING_BACK);
-
-    saveUpdate(update);
-    assertUpdate(update);
-    assertEquals(0, 
getUpdateDetails(updateId).get().getInstanceEvents().size());
-
-    saveJobInstanceEvent(event1, updateId);
-    assertEquals(
-        populateExpected(update, ROLLING_FORWARD, CREATED_MS, 125L),
-        getUpdateDetails(updateId).get().getUpdate());
-    assertEquals(
-        event1,
-        
Iterables.getOnlyElement(getUpdateDetails(updateId).get().getInstanceEvents()));
-    assertEquals(1L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_UPDATED)));
-
-    saveJobInstanceEvent(event2, updateId);
-    assertEquals(
-        populateExpected(update, ROLLING_FORWARD, CREATED_MS, 126L),
-        getUpdateDetails(updateId).get().getUpdate());
-    assertEquals(event1, 
getUpdateDetails(updateId).get().getInstanceEvents().get(0));
-    assertEquals(event2, 
getUpdateDetails(updateId).get().getInstanceEvents().get(1));
-    assertEquals(1L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_ROLLING_BACK)));
-  }
-
-  @Test(expected = StorageException.class)
-  public void testSaveJobEventWithoutUpdateFails() {
-    saveJobEvent(makeJobUpdateEvent(ROLLING_FORWARD, 123L), makeKey("u2"));
-  }
-
-  @Test(expected = StorageException.class)
-  public void testSaveInstanceEventWithoutUpdateFails() {
-    saveJobInstanceEvent(makeJobInstanceEvent(0, 125L, INSTANCE_UPDATED), 
makeKey("u1"));
-  }
-
   @Test
   public void testSaveJobUpdateStateIgnored() {
     IJobUpdateKey updateId = makeKey("u1");
-    IJobUpdate update = populateExpected(makeJobUpdate(updateId), ABORTED, 
567L, 567L);
+    IJobUpdateDetails update = withUpdateState(makeJobUpdate(updateId), 
ABORTED, 567L, 567L);
     saveUpdate(update);
 
     // Assert state fields were ignored.
-    assertUpdate(update);
+    assertUpdate(withDefaultUpdateState(update));
   }
 
   @Test
   public void testMultipleJobDetails() {
     IJobUpdateKey updateId1 = makeKey(JobKeys.from("role", "env", "name1"), 
"u1");
     IJobUpdateKey updateId2 = makeKey(JobKeys.from("role", "env", "name2"), 
"u2");
-    IJobUpdateDetails details1 = makeJobDetails(makeJobUpdate(updateId1));
-    IJobUpdateDetails details2 = makeJobDetails(makeJobUpdate(updateId2));
-
-    assertEquals(ImmutableList.of(), getInstanceEvents(updateId2, 3));
+    IJobUpdateDetails update1 = makeJobUpdate(updateId1);
+    IJobUpdateDetails update2 = makeJobUpdate(updateId2);
 
-    saveUpdate(details1.getUpdate());
-    saveUpdate(details2.getUpdate());
+    saveUpdate(update1);
+    saveUpdate(update2);
 
-    details1 = updateJobDetails(populateExpected(details1.getUpdate()), 
FIRST_EVENT);
-    details2 = updateJobDetails(populateExpected(details2.getUpdate()), 
FIRST_EVENT);
-    assertEquals(Optional.of(details1), getUpdateDetails(updateId1));
-    assertEquals(Optional.of(details2), getUpdateDetails(updateId2));
+    update1 = updateJobDetails(withDefaultUpdateState(update1), FIRST_EVENT);
+    update2 = updateJobDetails(withDefaultUpdateState(update2), FIRST_EVENT);
+    assertEquals(Optional.of(update1), getUpdateDetails(updateId1));
+    assertEquals(Optional.of(update2), getUpdateDetails(updateId2));
 
     IJobUpdateEvent jEvent11 = makeJobUpdateEvent(ROLLING_FORWARD, 456L);
     IJobUpdateEvent jEvent12 = makeJobUpdateEvent(ERROR, 457L);
@@ -413,168 +310,66 @@ public abstract class AbstractJobUpdateStoreTest {
     saveJobEvent(jEvent11, updateId1);
     saveJobEvent(jEvent12, updateId1);
     saveJobInstanceEvent(iEvent11, updateId1);
-    assertEquals(1L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_UPDATED)));
     saveJobInstanceEvent(iEvent12, updateId1);
-    assertEquals(1L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_UPDATING)));
 
     saveJobEvent(jEvent21, updateId2);
     saveJobEvent(jEvent22, updateId2);
     assertEquals(ImmutableList.of(), getInstanceEvents(updateId2, 3));
     saveJobInstanceEvent(iEvent21, updateId2);
-    assertEquals(2L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_UPDATING)));
 
     assertEquals(ImmutableList.of(iEvent21), getInstanceEvents(updateId2, 3));
     saveJobInstanceEvent(iEvent22, updateId2);
     assertEquals(ImmutableList.of(iEvent21, iEvent22), 
getInstanceEvents(updateId2, 3));
-    assertEquals(2L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_UPDATING)));
 
-    details1 = updateJobDetails(
-        populateExpected(details1.getUpdate(), ERROR, CREATED_MS, 457L),
+    update1 = updateJobDetails(
+        withUpdateState(update1, ERROR, CREATED_MS, 457L),
         ImmutableList.of(FIRST_EVENT, jEvent11, jEvent12), 
ImmutableList.of(iEvent11, iEvent12));
 
-    details2 = updateJobDetails(
-        populateExpected(details2.getUpdate(), ABORTED, CREATED_MS, 568L),
+    update2 = updateJobDetails(
+        withUpdateState(update2, ABORTED, CREATED_MS, 568L),
         ImmutableList.of(FIRST_EVENT, jEvent21, jEvent22), 
ImmutableList.of(iEvent21, iEvent22));
 
-    assertEquals(Optional.of(details1), getUpdateDetails(updateId1));
-    assertEquals(Optional.of(details2), getUpdateDetails(updateId2));
-
-    assertEquals(ImmutableSet.of(details1, details2), getAllUpdateDetails());
+    assertEquals(
+        ImmutableList.of(update2, update1),
+        fetchUpdates(JobUpdateStore.MATCH_ALL.newBuilder()));
 
     assertEquals(
         ImmutableList.of(getUpdateDetails(updateId2).get(), 
getUpdateDetails(updateId1).get()),
-        queryDetails(new JobUpdateQuery().setRole("role")));
+        fetchUpdates(new JobUpdateQuery().setRole("role")));
   }
 
   @Test
   public void testTruncateJobUpdates() {
-    IJobUpdateKey updateId = makeKey("u5");
-    IJobUpdate update = makeJobUpdate(updateId);
-    IJobInstanceUpdateEvent instanceEvent = IJobInstanceUpdateEvent.build(
-        new JobInstanceUpdateEvent(0, 125L, INSTANCE_ROLLBACK_FAILED));
-
-    saveUpdate(update);
-    saveJobEvent(makeJobUpdateEvent(ROLLING_FORWARD, 123L), updateId);
-    saveJobInstanceEvent(instanceEvent, updateId);
-    assertEquals(1L, 
stats.getLongValue(jobUpdateActionStatName(INSTANCE_ROLLBACK_FAILED)));
-    assertEquals(
-        populateExpected(update, ROLLING_FORWARD, CREATED_MS, 125L),
-        getUpdate(updateId).get());
-    assertEquals(2, getUpdateDetails(updateId).get().getUpdateEvents().size());
-    assertEquals(1, 
getUpdateDetails(updateId).get().getInstanceEvents().size());
-
+    saveUpdate(makeJobUpdate(makeKey("u1")));
+    saveUpdate(makeJobUpdate(makeKey("u2")));
+    assertEquals(2, fetchUpdates(new JobUpdateQuery()).size());
+    truncateUpdates();
+    assertEquals(0, fetchUpdates(new JobUpdateQuery()).size());
     truncateUpdates();
-    assertEquals(Optional.absent(), getUpdateDetails(updateId));
+    assertEquals(0, fetchUpdates(new JobUpdateQuery()).size());
   }
 
   @Test
-  public void testPruneHistory() {
-    IJobUpdateKey updateId1 = makeKey("u11");
-    IJobUpdateKey updateId2 = makeKey("u12");
-    IJobUpdateKey updateId3 = makeKey("u13");
-    IJobUpdateKey updateId4 = makeKey("u14");
-    IJobKey job2 = JobKeys.from("testRole2", "testEnv2", "job2");
-    IJobUpdateKey updateId5 = makeKey(job2, "u15");
-    IJobUpdateKey updateId6 = makeKey(job2, "u16");
-    IJobUpdateKey updateId7 = makeKey(job2, "u17");
-
-    IJobUpdate update1 = makeJobUpdate(updateId1);
-    IJobUpdate update2 = makeJobUpdate(updateId2);
-    IJobUpdate update3 = makeJobUpdate(updateId3);
-    IJobUpdate update4 = makeJobUpdate(updateId4);
-    IJobUpdate update5 = makeJobUpdate(updateId5);
-    IJobUpdate update6 = makeJobUpdate(updateId6);
-    IJobUpdate update7 = makeJobUpdate(updateId7);
-
-    IJobUpdateEvent updateEvent1 = makeJobUpdateEvent(ROLLING_BACK, 123L);
-    IJobUpdateEvent updateEvent2 = makeJobUpdateEvent(ABORTED, 124L);
-    IJobUpdateEvent updateEvent3 = makeJobUpdateEvent(ROLLED_BACK, 125L);
-    IJobUpdateEvent updateEvent4 = makeJobUpdateEvent(FAILED, 126L);
-    IJobUpdateEvent updateEvent5 = makeJobUpdateEvent(ERROR, 123L);
-    IJobUpdateEvent updateEvent6 = makeJobUpdateEvent(FAILED, 125L);
-    IJobUpdateEvent updateEvent7 = makeJobUpdateEvent(ROLLING_FORWARD, 126L);
-
-    update1 = populateExpected(saveUpdateNoEvent(update1), ROLLING_BACK, 123L, 
123L);
-    update2 = populateExpected(saveUpdateNoEvent(update2), ABORTED, 124L, 
124L);
-    update3 = populateExpected(saveUpdateNoEvent(update3), ROLLED_BACK, 125L, 
125L);
-    update4 = populateExpected(saveUpdateNoEvent(update4), FAILED, 126L, 126L);
-    update5 = populateExpected(saveUpdateNoEvent(update5), ERROR, 123L, 123L);
-    update6 = populateExpected(saveUpdateNoEvent(update6), FAILED, 125L, 125L);
-    update7 = populateExpected(saveUpdateNoEvent(update7), ROLLING_FORWARD, 
126L, 126L);
-
-    saveJobEvent(updateEvent1, updateId1);
-    saveJobEvent(updateEvent2, updateId2);
-    saveJobEvent(updateEvent3, updateId3);
-    saveJobEvent(updateEvent4, updateId4);
-    saveJobEvent(updateEvent5, updateId5);
-    saveJobEvent(updateEvent6, updateId6);
-    saveJobEvent(updateEvent7, updateId7);
-
-    assertEquals(update1, getUpdate(updateId1).get());
-    assertEquals(update2, getUpdate(updateId2).get());
-    assertEquals(update3, getUpdate(updateId3).get());
-    assertEquals(update4, getUpdate(updateId4).get());
-    assertEquals(update5, getUpdate(updateId5).get());
-    assertEquals(update6, getUpdate(updateId6).get());
-    assertEquals(update7, getUpdate(updateId7).get());
-
-    long pruningThreshold = 120L;
-
-    // No updates pruned.
-    assertEquals(ImmutableSet.of(), pruneHistory(3, pruningThreshold));
-    assertEquals(Optional.of(update7), getUpdate(updateId7)); // active update
-    assertEquals(Optional.of(update6), getUpdate(updateId6));
-    assertEquals(Optional.of(update5), getUpdate(updateId5));
-
-    assertEquals(Optional.of(update4), getUpdate(updateId4));
-    assertEquals(Optional.of(update3), getUpdate(updateId3));
-    assertEquals(Optional.of(update2), getUpdate(updateId2));
-    assertEquals(Optional.of(update1), getUpdate(updateId1)); // active update
-
-    assertEquals(ImmutableSet.of(updateId2), pruneHistory(2, 
pruningThreshold));
-    // No updates pruned.
-    assertEquals(Optional.of(update7), getUpdate(updateId7)); // active update
-    assertEquals(Optional.of(update6), getUpdate(updateId6));
-    assertEquals(Optional.of(update5), getUpdate(updateId5));
-
-    // 1 update pruned.
-    assertEquals(Optional.of(update4), getUpdate(updateId4));
-    assertEquals(Optional.of(update3), getUpdate(updateId3));
-    assertEquals(Optional.absent(), getUpdate(updateId2));
-    assertEquals(Optional.of(update1), getUpdate(updateId1)); // active update
-
-    assertEquals(ImmutableSet.of(updateId5, updateId3), pruneHistory(1, 
pruningThreshold));
-    // 1 update pruned.
-    assertEquals(Optional.of(update7), getUpdate(updateId7)); // active update
-    assertEquals(Optional.of(update6), getUpdate(updateId6));
-    assertEquals(Optional.absent(), getUpdate(updateId5));
-
-    // 2 updates pruned.
-    assertEquals(Optional.of(update4), getUpdate(updateId4));
-    assertEquals(Optional.absent(), getUpdate(updateId3));
-    assertEquals(Optional.of(update1), getUpdate(updateId1)); // active update
-
-    // The oldest update is pruned.
-    assertEquals(ImmutableSet.of(updateId6), pruneHistory(1, 126L));
-    assertEquals(Optional.of(update7), getUpdate(updateId7)); // active update
-    assertEquals(Optional.absent(), getUpdate(updateId6));
+  public void testRemoveUpdates() {
+    IJobUpdateDetails u1 = makeJobUpdate(makeKey("u1"));
+    IJobUpdateDetails u2 = makeJobUpdate(makeKey("u2"));
+    IJobUpdateDetails u3 = makeJobUpdate(makeKey("u3"));
+    saveUpdate(u1);
+    saveUpdate(u2);
+    saveUpdate(u3);
 
-    assertEquals(Optional.of(update4), getUpdate(updateId4));
-    assertEquals(Optional.of(update1), getUpdate(updateId1)); // active update
+    storage.write((NoResult.Quiet) store ->
+        store.getJobUpdateStore().removeJobUpdates(ImmutableSet.of(key(u1), 
key(u3))));
+    assertQueryMatches(new JobUpdateQuery(), withDefaultUpdateState(u2));
 
-    // Nothing survives the 0 per job count.
-    assertEquals(ImmutableSet.of(updateId4), pruneHistory(0, 
pruningThreshold));
-    assertEquals(Optional.of(update7), getUpdate(updateId7)); // active update
+    // Noop - update already deleted
+    storage.write((NoResult.Quiet) store ->
+        store.getJobUpdateStore().removeJobUpdates(ImmutableSet.of(key(u1))));
+    assertQueryMatches(new JobUpdateQuery(), withDefaultUpdateState(u2));
 
-    assertEquals(Optional.absent(), getUpdate(updateId4));
-    assertEquals(Optional.of(update1), getUpdate(updateId1)); // active update
-  }
-
-  @Test(expected = StorageException.class)
-  public void testSaveTwoUpdatesForOneJob() {
-    IJobUpdate update = makeJobUpdate(makeKey("updateId"));
-    saveUpdate(update);
-    saveUpdate(update);
+    storage.write((NoResult.Quiet) store ->
+        store.getJobUpdateStore().removeJobUpdates(ImmutableSet.of(key(u2))));
+    assertQueryMatches(new JobUpdateQuery());
   }
 
   @Test
@@ -583,114 +378,31 @@ public abstract class AbstractJobUpdateStoreTest {
 
     ImmutableSet<Metadata> duplicatedMetadata =
         ImmutableSet.of(new Metadata("k1", "v1"), new Metadata("k1", "v2"));
-    JobUpdate builder = makeJobUpdate(updateId).newBuilder();
-    builder.getSummary().setMetadata(duplicatedMetadata);
-    IJobUpdate update = IJobUpdate.build(builder);
+    JobUpdateDetails builder = makeJobUpdate(updateId).newBuilder();
+    builder.getUpdate().getSummary().setMetadata(duplicatedMetadata);
 
     assertEquals(Optional.absent(), getUpdate(updateId));
 
+    IJobUpdateDetails update = IJobUpdateDetails.build(builder);
     saveUpdate(update);
     assertUpdate(update);
   }
 
   @Test
-  public void testGetSummaries() {
-    String role1 = "role1";
-    IJobKey job1 = JobKeys.from(role1, "env", "name1");
-    IJobKey job2 = JobKeys.from(role1, "env", "name2");
-    IJobKey job3 = JobKeys.from(role1, "env", "name3");
-    IJobKey job4 = JobKeys.from(role1, "env", "name4");
-    IJobKey job5 = JobKeys.from("role", "env", "name5");
-    IJobUpdateSummary s1 = saveSummary(makeKey(job1, "u1"), 1230L, 
ROLLED_BACK, "user");
-    IJobUpdateSummary s2 = saveSummary(makeKey(job2, "u2"), 1231L, ABORTED, 
"user");
-    IJobUpdateSummary s3 = saveSummary(makeKey(job3, "u3"), 1239L, ERROR, 
"user2");
-    IJobUpdateSummary s4 = saveSummary(makeKey(job4, "u4"), 1234L, 
ROLL_BACK_PAUSED, "user3");
-    IJobUpdateSummary s5 = saveSummary(makeKey(job5, "u5"), 1235L, 
ROLLING_FORWARD, "user4");
-
-    // Test empty query returns all.
-    assertEquals(ImmutableList.of(s3, s5, s4, s2, s1), getSummaries(new 
JobUpdateQuery()));
-
-    // Test query by updateId.
-    assertEquals(
-        ImmutableList.of(s1),
-        getSummaries(new JobUpdateQuery().setKey(new 
JobUpdateKey(job1.newBuilder(), "u1"))));
-
-    // Test query by role.
-    assertEquals(
-        ImmutableList.of(s3, s4, s2, s1),
-        getSummaries(new JobUpdateQuery().setRole(role1)));
-
-    // Test query by job key.
-    assertEquals(
-        ImmutableList.of(s5),
-        getSummaries(new JobUpdateQuery().setJobKey(job5.newBuilder())));
-
-    // Test querying by update key.
-    assertEquals(
-        ImmutableList.of(s5),
-        getSummaries(
-            new JobUpdateQuery().setKey(new JobUpdateKey(job5.newBuilder(), 
s5.getKey().getId()))));
-
-    // Test querying by incorrect update keys.
-    assertEquals(
-        ImmutableList.of(),
-        getSummaries(
-            new JobUpdateQuery().setKey(new JobUpdateKey(job5.newBuilder(), 
s4.getKey().getId()))));
-    assertEquals(
-        ImmutableList.of(),
-        getSummaries(
-            new JobUpdateQuery().setKey(new JobUpdateKey(job4.newBuilder(), 
s5.getKey().getId()))));
-
-    // Test query by user.
-    assertEquals(ImmutableList.of(s2, s1), getSummaries(new 
JobUpdateQuery().setUser("user")));
-
-    // Test query by one status.
-    assertEquals(ImmutableList.of(s3), getSummaries(new 
JobUpdateQuery().setUpdateStatuses(
-        ImmutableSet.of(ERROR))));
-
-    // Test query by multiple statuses.
-    assertEquals(ImmutableList.of(s3, s2, s1), getSummaries(new 
JobUpdateQuery().setUpdateStatuses(
-        ImmutableSet.of(ERROR, ABORTED, ROLLED_BACK))));
-
-    // Test query by empty statuses.
-    assertEquals(
-        ImmutableList.of(s3, s5, s4, s2, s1),
-        getSummaries(new 
JobUpdateQuery().setUpdateStatuses(ImmutableSet.of())));
-
-    // Test paging.
-    assertEquals(
-        ImmutableList.of(s3, s5),
-        getSummaries(new JobUpdateQuery().setLimit(2).setOffset(0)));
-    assertEquals(
-        ImmutableList.of(s4, s2),
-        getSummaries(new JobUpdateQuery().setLimit(2).setOffset(2)));
-    assertEquals(
-        ImmutableList.of(s1),
-        getSummaries(new JobUpdateQuery().setLimit(2).setOffset(4)));
-
-    // Test no match.
-    assertEquals(
-        ImmutableList.of(),
-        getSummaries(new JobUpdateQuery().setRole("no_match")));
-  }
-
-  @Test
   public void testQueryDetails() {
     IJobKey jobKey1 = JobKeys.from("role1", "env", "name1");
     IJobUpdateKey updateId1 = makeKey(jobKey1, "u1");
     IJobKey jobKey2 = JobKeys.from("role2", "env", "name2");
     IJobUpdateKey updateId2 = makeKey(jobKey2, "u2");
 
-    IJobUpdate update1 = makeJobUpdate(updateId1);
-    IJobUpdate update2 = makeJobUpdate(updateId2);
-
-    assertEquals(ImmutableList.of(), getInstanceEvents(updateId2, 3));
+    IJobUpdateDetails update1 = makeJobUpdate(updateId1);
+    IJobUpdateDetails update2 = makeJobUpdate(updateId2);
 
     saveUpdate(update1);
     saveUpdate(update2);
 
-    updateJobDetails(populateExpected(update1), FIRST_EVENT);
-    updateJobDetails(populateExpected(update2), FIRST_EVENT);
+    updateJobDetails(withDefaultUpdateState(update1), FIRST_EVENT);
+    updateJobDetails(withDefaultUpdateState(update2), FIRST_EVENT);
 
     IJobUpdateEvent jEvent11 = makeJobUpdateEvent(ROLLING_BACK, 450L);
     IJobUpdateEvent jEvent12 = makeJobUpdateEvent(ROLLED_BACK, 500L);
@@ -713,57 +425,60 @@ public abstract class AbstractJobUpdateStoreTest {
     saveJobInstanceEvent(iEvent21, updateId2);
     saveJobInstanceEvent(iEvent22, updateId2);
 
-    IJobUpdateDetails details1 = getUpdateDetails(updateId1).get();
-    IJobUpdateDetails details2 = getUpdateDetails(updateId2).get();
+    // Fetch the updates for checking query results.  This avoids the need to 
manually populate
+    // any fields filled by the storage, which is out of scope for this test 
case.
+    update1 = getUpdateDetails(updateId1).get();
+    update2 = getUpdateDetails(updateId2).get();
 
-    // Test empty query returns all.
-    assertEquals(ImmutableList.of(details2, details1), queryDetails(new 
JobUpdateQuery()));
+    // Empty query returns all.
+    assertQueryMatches(new JobUpdateQuery(), update2, update1);
 
-    // Test query by update ID.
-    assertEquals(
-        ImmutableList.of(details1),
-        queryDetails(new JobUpdateQuery().setKey(updateId1.newBuilder())));
+    // Query by update ID.
+    assertQueryMatches(new JobUpdateQuery().setKey(updateId1.newBuilder()), 
update1);
 
-    // Test query by role.
-    assertEquals(
-        ImmutableList.of(details2),
-        queryDetails(new JobUpdateQuery().setRole(jobKey2.getRole())));
+    // Query by role.
+    assertQueryMatches(new JobUpdateQuery().setRole(jobKey2.getRole()), 
update2);
 
-    // Test query by job key.
-    assertEquals(
-        ImmutableList.of(details2),
-        queryDetails(new JobUpdateQuery().setJobKey(jobKey2.newBuilder())));
+    // Query by job key.
+    assertQueryMatches(new JobUpdateQuery().setJobKey(jobKey2.newBuilder()), 
update2);
 
-    // Test query by status.
-    assertEquals(
-        ImmutableList.of(details2),
-        queryDetails(new 
JobUpdateQuery().setUpdateStatuses(ImmutableSet.of(ABORTED))));
+    // Query by status.
+    assertQueryMatches(new 
JobUpdateQuery().setUpdateStatuses(ImmutableSet.of(ABORTED)), update2);
 
-    // Test no match.
-    assertEquals(
-        ImmutableList.of(),
-        queryDetails(new JobUpdateQuery().setRole("no match")));
-  }
+    // No match.
+    assertQueryMatches(new JobUpdateQuery().setRole("no match"));
 
-  @Test
-  public void testSaveEventsOutOfChronologicalOrder() {
-    IJobUpdate update1 = makeJobUpdate(UPDATE1);
-    saveUpdate(update1);
+    // Querying by incorrect update keys.
+    assertQueryMatches(new JobUpdateQuery().setJobKey(JobKeys.from("a", "b", 
"c").newBuilder()));
+
+    // Query by multiple statuses.
+    assertQueryMatches(
+        new JobUpdateQuery().setUpdateStatuses(ImmutableSet.of(ABORTED, 
ROLLING_FORWARD)),
+        update2);
+
+    // Query by empty statuses.
+    assertQueryMatches(new 
JobUpdateQuery().setUpdateStatuses(ImmutableSet.of()), update2, update1);
 
-    IJobUpdateEvent event2 = makeJobUpdateEvent(ROLLING_FORWARD, 124);
-    IJobUpdateEvent event1 = makeJobUpdateEvent(ROLL_FORWARD_PAUSED, 122);
-    saveJobEvent(event2, UPDATE1);
-    saveJobEvent(event1, UPDATE1);
+    // Query by user.
+    assertQueryMatches(new JobUpdateQuery().setUser("user"), update2, update1);
 
-    IJobInstanceUpdateEvent instanceEvent2 = makeJobInstanceEvent(0, 125, 
INSTANCE_UPDATED);
-    IJobInstanceUpdateEvent instanceEvent1 = makeJobInstanceEvent(0, 124, 
INSTANCE_UPDATING);
+    // Test paging.
+    assertQueryMatches(new JobUpdateQuery().setLimit(1).setOffset(0), update2);
+    assertQueryMatches(new JobUpdateQuery().setLimit(2).setOffset(0), update2, 
update1);
+    assertQueryMatches(new JobUpdateQuery().setLimit(3).setOffset(0), update2, 
update1);
+    assertQueryMatches(new JobUpdateQuery().setLimit(1).setOffset(1), update1);
+    assertQueryMatches(new JobUpdateQuery().setLimit(2).setOffset(4));
+  }
 
-    saveJobInstanceEvent(instanceEvent2, UPDATE1);
-    saveJobInstanceEvent(instanceEvent1, UPDATE1);
+  private static IJobUpdateKey key(IJobUpdateDetails update) {
+    return update.getUpdate().getSummary().getKey();
+  }
 
-    IJobUpdateState state = 
getUpdateDetails(UPDATE1).get().getUpdate().getSummary().getState();
-    assertEquals(ROLLING_FORWARD, state.getStatus());
-    assertEquals(125, state.getLastModifiedTimestampMs());
+  private void assertQueryMatches(JobUpdateQuery query, IJobUpdateDetails... 
matches) {
+    assertEquals(
+        ImmutableList.copyOf(matches),
+        storage.read(store ->
+            
store.getJobUpdateStore().fetchJobUpdates(IJobUpdateQuery.build(query))));
   }
 
   private static IJobUpdateKey makeKey(String id) {
@@ -774,63 +489,43 @@ public abstract class AbstractJobUpdateStoreTest {
     return IJobUpdateKey.build(new JobUpdateKey(job.newBuilder(), id));
   }
 
-  private void assertUpdate(IJobUpdate expected) {
-    IJobUpdateKey key = expected.getSummary().getKey();
-    assertEquals(populateExpected(expected), getUpdate(key).get());
-    assertEquals(getUpdate(key).get(), 
getUpdateDetails(key).get().getUpdate());
-    assertEquals(getUpdateInstructions(key).get(), expected.getInstructions());
+  private void assertUpdate(IJobUpdateDetails expected) {
+    assertEquals(withDefaultUpdateState(expected), 
getUpdate(key(expected)).get());
   }
 
-  private Optional<IJobUpdate> getUpdate(IJobUpdateKey key) {
+  private Optional<IJobUpdateDetails> getUpdate(IJobUpdateKey key) {
     return storage.read(storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdate(key));
   }
 
   private List<IJobInstanceUpdateEvent> getInstanceEvents(IJobUpdateKey key, 
int id) {
-    return storage.read(
-        storeProvider -> 
storeProvider.getJobUpdateStore().fetchInstanceEvents(key, id));
-  }
-
-  private Optional<IJobUpdateInstructions> getUpdateInstructions(IJobUpdateKey 
key) {
-    return storage.read(
-        storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdateInstructions(key));
+    IJobUpdateDetails update =
+        storage.read(store -> 
store.getJobUpdateStore().fetchJobUpdate(key).get());
+    return update.getInstanceEvents().stream()
+        .filter(e -> e.getInstanceId() == id)
+        .collect(Collectors.toList());
   }
 
   private Optional<IJobUpdateDetails> getUpdateDetails(IJobUpdateKey key) {
-    return storage.read(
-        storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdateDetails(key));
-  }
-
-  private Set<IJobUpdateDetails> getAllUpdateDetails() {
-    return storage.read(
-        storeProvider -> 
storeProvider.getJobUpdateStore().fetchAllJobUpdateDetails());
-  }
-
-  private List<IJobUpdateDetails> queryDetails(JobUpdateQuery query) {
-    return storage.read(storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdateDetails(
-        IJobUpdateQuery.build(query)));
+    return storage.read(storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdate(key));
   }
 
-  private List<IJobUpdateSummary> getSummaries(JobUpdateQuery query) {
-    return storage.read(storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdateSummaries(
-        IJobUpdateQuery.build(query)));
+  private List<IJobUpdateDetails> fetchUpdates(JobUpdateQuery query) {
+    return storage.read(storeProvider ->
+        
storeProvider.getJobUpdateStore().fetchJobUpdates(IJobUpdateQuery.build(query)));
   }
 
-  private IJobUpdate saveUpdate(IJobUpdate update) {
+  private void saveUpdate(IJobUpdateDetails update) {
     storage.write((NoResult.Quiet) storeProvider -> {
-      storeProvider.getJobUpdateStore().saveJobUpdate(update);
-      storeProvider.getJobUpdateStore().saveJobUpdateEvent(
-          update.getSummary().getKey(),
-          FIRST_EVENT);
+      JobUpdateStore.Mutable store = storeProvider.getJobUpdateStore();
+      store.saveJobUpdate(update.getUpdate());
+      IJobUpdateKey key = update.getUpdate().getSummary().getKey();
+      update.getUpdateEvents().forEach(event -> {
+        store.saveJobUpdateEvent(key, event);
+      });
+      update.getInstanceEvents().forEach(event -> {
+        store.saveJobInstanceUpdateEvent(key, event);
+      });
     });
-
-    return update;
-  }
-
-  private IJobUpdate saveUpdateNoEvent(IJobUpdate update) {
-    storage.write((NoResult.Quiet) storeProvider ->
-        storeProvider.getJobUpdateStore().saveJobUpdate(update));
-
-    return update;
   }
 
   private void saveJobEvent(IJobUpdateEvent event, IJobUpdateKey key) {
@@ -845,20 +540,15 @@ public abstract class AbstractJobUpdateStoreTest {
 
   private void truncateUpdates() {
     storage.write((NoResult.Quiet)
-        storeProvider -> 
storeProvider.getJobUpdateStore().deleteAllUpdatesAndEvents());
-  }
-
-  private Set<IJobUpdateKey> pruneHistory(int retainCount, long 
pruningThresholdMs) {
-    return storage.write(storeProvider ->
-        storeProvider.getJobUpdateStore().pruneHistory(retainCount, 
pruningThresholdMs));
+        storeProvider -> storeProvider.getJobUpdateStore().deleteAllUpdates());
   }
 
-  private IJobUpdate populateExpected(IJobUpdate update) {
-    return populateExpected(update, ROLLING_FORWARD, CREATED_MS, CREATED_MS);
+  private IJobUpdateDetails withDefaultUpdateState(IJobUpdateDetails update) {
+    return withUpdateState(update, ROLLING_FORWARD, CREATED_MS, CREATED_MS);
   }
 
-  private IJobUpdate populateExpected(
-      IJobUpdate update,
+  private IJobUpdateDetails withUpdateState(
+      IJobUpdateDetails update,
       JobUpdateStatus status,
       long createdMs,
       long lastMs) {
@@ -867,9 +557,9 @@ public abstract class AbstractJobUpdateStoreTest {
         .setCreatedTimestampMs(createdMs)
         .setLastModifiedTimestampMs(lastMs)
         .setStatus(status);
-    JobUpdate builder = update.newBuilder();
-    builder.getSummary().setState(state);
-    return IJobUpdate.build(builder);
+    JobUpdateDetails builder = update.newBuilder();
+    builder.getUpdate().getSummary().setState(state);
+    return IJobUpdateDetails.build(builder);
   }
 
   private static IJobUpdateEvent makeJobUpdateEvent(JobUpdateStatus status, 
long timestampMs) {
@@ -888,14 +578,7 @@ public abstract class AbstractJobUpdateStoreTest {
         new JobInstanceUpdateEvent(instanceId, timestampMs, action));
   }
 
-  private IJobUpdateDetails makeJobDetails(IJobUpdate update) {
-    return updateJobDetails(
-        update,
-        ImmutableList.of(FIRST_EVENT),
-        ImmutableList.of());
-  }
-
-  private IJobUpdateDetails updateJobDetails(IJobUpdate update, 
IJobUpdateEvent event) {
+  private IJobUpdateDetails updateJobDetails(IJobUpdateDetails update, 
IJobUpdateEvent event) {
     return updateJobDetails(
         update,
         ImmutableList.of(event),
@@ -903,12 +586,11 @@ public abstract class AbstractJobUpdateStoreTest {
   }
 
   private IJobUpdateDetails updateJobDetails(
-      IJobUpdate update,
+      IJobUpdateDetails update,
       List<IJobUpdateEvent> jobEvents,
       List<IJobInstanceUpdateEvent> instanceEvents) {
 
-    return IJobUpdateDetails.build(new JobUpdateDetails()
-        .setUpdate(update.newBuilder())
+    return IJobUpdateDetails.build(update.newBuilder()
         .setUpdateEvents(IJobUpdateEvent.toBuildersList(jobEvents))
         
.setInstanceEvents(IJobInstanceUpdateEvent.toBuildersList(instanceEvents)));
   }
@@ -920,35 +602,12 @@ public abstract class AbstractJobUpdateStoreTest {
         .setMetadata(METADATA));
   }
 
-  private IJobUpdateSummary saveSummary(
-      IJobUpdateKey key,
-      Long modifiedTimestampMs,
-      JobUpdateStatus status,
-      String user) {
-
-    IJobUpdateSummary summary = IJobUpdateSummary.build(new JobUpdateSummary()
-        .setKey(key.newBuilder())
-        .setUser(user)
-        .setMetadata(METADATA));
-
-    IJobUpdate update = makeJobUpdate(summary);
-    saveUpdate(update);
-    saveJobEvent(makeJobUpdateEvent(status, modifiedTimestampMs), key);
-    return populateExpected(update, status, CREATED_MS, 
modifiedTimestampMs).getSummary();
-  }
-
-  private IJobUpdate makeJobUpdate(IJobUpdateSummary summary) {
-    return 
IJobUpdate.build(makeJobUpdate().newBuilder().setSummary(summary.newBuilder()));
-  }
-
-  private static IJobUpdate makeJobUpdate(IJobUpdateKey key) {
-    return IJobUpdate.build(makeJobUpdate().newBuilder()
-        .setSummary(makeSummary(key, "user").newBuilder()));
-  }
-
-  private static IJobUpdate makeJobUpdate() {
-    return IJobUpdate.build(new JobUpdate()
-        .setInstructions(makeJobUpdateInstructions().newBuilder()));
+  private static IJobUpdateDetails makeJobUpdate(IJobUpdateKey key) {
+    return IJobUpdateDetails.build(new JobUpdateDetails()
+        .setUpdateEvents(ImmutableList.of(FIRST_EVENT.newBuilder()))
+        .setUpdate(new JobUpdate()
+            .setInstructions(makeJobUpdateInstructions().newBuilder())
+            .setSummary(makeSummary(key, "user").newBuilder())));
   }
 
   private static IJobUpdateInstructions makeJobUpdateInstructions() {

http://git-wip-us.apache.org/repos/asf/aurora/blob/284f40f5/src/test/java/org/apache/aurora/scheduler/storage/log/LogStorageTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/storage/log/LogStorageTest.java 
b/src/test/java/org/apache/aurora/scheduler/storage/log/LogStorageTest.java
index c208210..3c056c9 100644
--- a/src/test/java/org/apache/aurora/scheduler/storage/log/LogStorageTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/storage/log/LogStorageTest.java
@@ -59,6 +59,7 @@ import org.apache.aurora.gen.storage.LogEntry;
 import org.apache.aurora.gen.storage.Op;
 import org.apache.aurora.gen.storage.PruneJobUpdateHistory;
 import org.apache.aurora.gen.storage.RemoveJob;
+import org.apache.aurora.gen.storage.RemoveJobUpdates;
 import org.apache.aurora.gen.storage.RemoveQuota;
 import org.apache.aurora.gen.storage.RemoveTasks;
 import org.apache.aurora.gen.storage.SaveCronJob;
@@ -126,7 +127,7 @@ public class LogStorageTest extends EasyMockTest {
   private static final IJobKey JOB_KEY = JobKeys.from("role", "env", "name");
   private static final IJobUpdateKey UPDATE_ID =
       IJobUpdateKey.build(new JobUpdateKey(JOB_KEY.newBuilder(), 
"testUpdateId"));
-  private static final long NOW = 42L;
+  private static final long NOW = 42;
 
   private LogStorage logStorage;
   private Log log;
@@ -350,8 +351,11 @@ public class LogStorageTest extends EasyMockTest {
         IJobInstanceUpdateEvent.build(saveInstanceEvent.getEvent()));
 
     builder.add(createTransaction(Op.pruneJobUpdateHistory(new 
PruneJobUpdateHistory(5, 10L))));
-    expect(storageUtil.jobUpdateStore.pruneHistory(5, 10L))
-        
.andReturn(ImmutableSet.of(IJobUpdateKey.build(UPDATE_ID.newBuilder())));
+    // No expectation - this op is ignored.
+
+    builder.add(createTransaction(Op.removeJobUpdate(
+        new 
RemoveJobUpdates().setKeys(ImmutableSet.of(UPDATE_ID.newBuilder())))));
+    storageUtil.jobUpdateStore.removeJobUpdates(ImmutableSet.of(UPDATE_ID));
 
     // NOOP LogEntry
     builder.add(LogEntry.noop(true));
@@ -856,28 +860,24 @@ public class LogStorageTest extends EasyMockTest {
   }
 
   @Test
-  public void testPruneHistory() throws Exception {
-    PruneJobUpdateHistory pruneHistory = new PruneJobUpdateHistory()
-        .setHistoryPruneThresholdMs(1L)
-        .setPerJobRetainCount(1);
+  public void testRemoveJobUpdates() throws Exception {
+    IJobUpdateKey key = IJobUpdateKey.build(new JobUpdateKey()
+        .setJob(JOB_KEY.newBuilder())
+        .setId("update-id"));
 
     new AbstractMutationFixture() {
       @Override
       protected void setupExpectations() throws Exception {
         storageUtil.expectWrite();
-        expect(storageUtil.jobUpdateStore.pruneHistory(
-            pruneHistory.getPerJobRetainCount(),
-            pruneHistory.getHistoryPruneThresholdMs()))
-            .andReturn(ImmutableSet.of(UPDATE_ID));
+        storageUtil.jobUpdateStore.removeJobUpdates(ImmutableSet.of(key));
 
-        
streamMatcher.expectTransaction(Op.pruneJobUpdateHistory(pruneHistory)).andReturn(position);
+        // No log transaction is generated since this version is currently in 
'read-only'
+        // compatibility mode for this operation type.
       }
 
       @Override
       protected void performMutations(MutableStoreProvider storeProvider) {
-        storeProvider.getJobUpdateStore().pruneHistory(
-            pruneHistory.getPerJobRetainCount(),
-            pruneHistory.getHistoryPruneThresholdMs());
+        
storeProvider.getJobUpdateStore().removeJobUpdates(ImmutableSet.of(key));
       }
     }.run();
   }

http://git-wip-us.apache.org/repos/asf/aurora/blob/284f40f5/src/test/java/org/apache/aurora/scheduler/storage/log/WriteAheadStorageTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/storage/log/WriteAheadStorageTest.java
 
b/src/test/java/org/apache/aurora/scheduler/storage/log/WriteAheadStorageTest.java
index d5e5c11..8a99b36 100644
--- 
a/src/test/java/org/apache/aurora/scheduler/storage/log/WriteAheadStorageTest.java
+++ 
b/src/test/java/org/apache/aurora/scheduler/storage/log/WriteAheadStorageTest.java
@@ -25,10 +25,8 @@ import org.apache.aurora.gen.HostAttributes;
 import org.apache.aurora.gen.JobUpdateKey;
 import org.apache.aurora.gen.MaintenanceMode;
 import org.apache.aurora.gen.storage.Op;
-import org.apache.aurora.gen.storage.PruneJobUpdateHistory;
 import org.apache.aurora.gen.storage.SaveHostAttributes;
 import org.apache.aurora.gen.storage.SaveTasks;
-import org.apache.aurora.scheduler.base.JobKeys;
 import org.apache.aurora.scheduler.base.TaskTestUtil;
 import org.apache.aurora.scheduler.events.EventSink;
 import org.apache.aurora.scheduler.events.PubsubEvent;
@@ -85,26 +83,16 @@ public class WriteAheadStorageTest extends EasyMockTest {
   }
 
   @Test
-  public void testPruneHistory() {
-    Set<IJobUpdateKey> pruned = ImmutableSet.of(
-        IJobUpdateKey.build(new JobUpdateKey(JobKeys.from("role", "env", 
"job").newBuilder(), "a")),
-        IJobUpdateKey.build(
-            new JobUpdateKey(JobKeys.from("role", "env", "job").newBuilder(), 
"b")));
-    expect(jobUpdateStore.pruneHistory(1, 1)).andReturn(pruned);
-    expectOp(Op.pruneJobUpdateHistory(new PruneJobUpdateHistory(1, 1)));
+  public void testRemoveUpdates() {
+    Set<IJobUpdateKey> removed = ImmutableSet.of(
+        IJobUpdateKey.build(new JobUpdateKey(TaskTestUtil.JOB.newBuilder(), 
"a")),
+        IJobUpdateKey.build(new JobUpdateKey(TaskTestUtil.JOB.newBuilder(), 
"b")));
+    jobUpdateStore.removeJobUpdates(removed);
+    // No operation is written since this Op is in read-only compatibility 
mode.
 
     control.replay();
 
-    storage.pruneHistory(1, 1);
-  }
-
-  @Test
-  public void testNoopPruneHistory() {
-    expect(jobUpdateStore.pruneHistory(1, 1)).andReturn(ImmutableSet.of());
-
-    control.replay();
-
-    storage.pruneHistory(1, 1);
+    storage.removeJobUpdates(removed);
   }
 
   @Test
@@ -172,6 +160,6 @@ public class WriteAheadStorageTest extends EasyMockTest {
   @Test(expected = UnsupportedOperationException.class)
   public void testDeleteAllUpdatesAndEvents() {
     control.replay();
-    storage.deleteAllUpdatesAndEvents();
+    storage.deleteAllUpdates();
   }
 }

http://git-wip-us.apache.org/repos/asf/aurora/blob/284f40f5/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
 
b/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
index 39456cf..312e5e0 100644
--- 
a/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
+++ 
b/src/test/java/org/apache/aurora/scheduler/thrift/ReadOnlySchedulerImplTest.java
@@ -16,8 +16,8 @@ package org.apache.aurora.scheduler.thrift;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
-
 import java.util.stream.Collectors;
+
 import javax.annotation.Nullable;
 
 import com.google.common.base.Function;
@@ -83,7 +83,6 @@ import 
org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
 import org.apache.aurora.scheduler.storage.entities.IJobKey;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateDetails;
 import org.apache.aurora.scheduler.storage.entities.IJobUpdateQuery;
-import org.apache.aurora.scheduler.storage.entities.IJobUpdateSummary;
 import org.apache.aurora.scheduler.storage.entities.IRange;
 import org.apache.aurora.scheduler.storage.entities.IResponse;
 import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
@@ -590,22 +589,22 @@ public class ReadOnlySchedulerImplTest extends 
EasyMockTest {
   @Test
   public void testGetJobUpdateSummaries() throws Exception {
     JobUpdateQuery query = new JobUpdateQuery().setRole(ROLE);
-    List<JobUpdateSummary> summaries = createJobUpdateSummaries(5);
-    
expect(storageUtil.jobUpdateStore.fetchJobUpdateSummaries(IJobUpdateQuery.build(query)))
-        .andReturn(IJobUpdateSummary.listFromBuilders(summaries));
+    Set<JobUpdateDetails> details = createJobUpdateDetails(5);
+    
expect(storageUtil.jobUpdateStore.fetchJobUpdates(IJobUpdateQuery.build(query)))
+        .andReturn(IJobUpdateDetails.listFromBuilders(details));
 
     control.replay();
 
     Response response = assertOkResponse(thrift.getJobUpdateSummaries(query));
     assertEquals(
-        summaries,
+        details.stream().map(u -> 
u.getUpdate().getSummary()).collect(Collectors.toList()),
         
response.getResult().getGetJobUpdateSummariesResult().getUpdateSummaries());
   }
 
   @Test
   public void testGetJobUpdateDetails() throws Exception {
     JobUpdateDetails details = createJobUpdateDetails();
-    expect(storageUtil.jobUpdateStore.fetchJobUpdateDetails(UPDATE_KEY))
+    expect(storageUtil.jobUpdateStore.fetchJobUpdate(UPDATE_KEY))
         .andReturn(Optional.of(IJobUpdateDetails.build(details)));
 
     control.replay();
@@ -622,7 +621,7 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest 
{
   public void testGetJobUpdateDetailsQuery() throws Exception {
     JobUpdateQuery query = new JobUpdateQuery().setRole(ROLE);
     List<IJobUpdateDetails> details = 
IJobUpdateDetails.listFromBuilders(createJobUpdateDetails(5));
-    
expect(storageUtil.jobUpdateStore.fetchJobUpdateDetails(IJobUpdateQuery.build(query)))
+    
expect(storageUtil.jobUpdateStore.fetchJobUpdates(IJobUpdateQuery.build(query)))
         .andReturn(details);
 
     control.replay();
@@ -644,16 +643,16 @@ public class ReadOnlySchedulerImplTest extends 
EasyMockTest {
     return builder.build();
   }
 
-  private static List<JobUpdateDetails> createJobUpdateDetails(int count) {
+  private static Set<JobUpdateDetails> createJobUpdateDetails(int count) {
     List<JobUpdateSummary> summaries = createJobUpdateSummaries(count);
     return summaries.stream()
         .map(jobUpdateSummary ->
             new JobUpdateDetails().setUpdate(new 
JobUpdate().setSummary(jobUpdateSummary)))
-        .collect(Collectors.toList());
+        .collect(Collectors.toSet());
   }
 
   private static JobUpdateDetails createJobUpdateDetails() {
-    return createJobUpdateDetails(1).get(0);
+    return createJobUpdateDetails(1).stream().findFirst().get();
   }
 
   @Test
@@ -739,7 +738,7 @@ public class ReadOnlySchedulerImplTest extends EasyMockTest 
{
 
   @Test
   public void testGetJobUpdateDetailsInvalidId() throws Exception {
-    expect(storageUtil.jobUpdateStore.fetchJobUpdateDetails(UPDATE_KEY))
+    expect(storageUtil.jobUpdateStore.fetchJobUpdate(UPDATE_KEY))
         .andReturn(Optional.absent());
 
     control.replay();

http://git-wip-us.apache.org/repos/asf/aurora/blob/284f40f5/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java 
b/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
index 661ce58..92f2582 100644
--- a/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
+++ b/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
@@ -249,12 +249,12 @@ public class JobUpdaterIT extends EasyMockTest {
 
   private IJobUpdateDetails getDetails() {
     return storage.read(
-        storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdateDetails(UPDATE_ID).get());
+        storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdate(UPDATE_ID).get());
   }
 
   private IJobUpdateDetails getDetails(IJobUpdateKey key) {
     return storage.read(
-        storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdateDetails(key).get());
+        storeProvider -> 
storeProvider.getJobUpdateStore().fetchJobUpdate(key).get());
   }
 
   private void assertLatestUpdateMessage(String expected) {
@@ -709,7 +709,7 @@ public class JobUpdaterIT extends EasyMockTest {
     assertState(ROLL_FORWARD_AWAITING_PULSE, actions.build());
 
     storage.write((NoResult.Quiet) storeProvider -> {
-      storeProvider.getJobUpdateStore().deleteAllUpdatesAndEvents();
+      storeProvider.getJobUpdateStore().deleteAllUpdates();
     });
 
     // The pulse still returns OK but the error is handled.
@@ -1099,7 +1099,7 @@ public class JobUpdaterIT extends EasyMockTest {
 
     storage.write((NoResult.Quiet) storeProvider -> {
       JobUpdateStore.Mutable store = storeProvider.getJobUpdateStore();
-      store.deleteAllUpdatesAndEvents();
+      store.deleteAllUpdates();
 
       JobUpdate builder = update.newBuilder();
       builder.getInstructions().getSettings().setUpdateGroupSize(0);

Reply via email to