Repository: aurora Updated Branches: refs/heads/master d98bfc8f4 -> 26644fcc5
Restore build properties within Scheduler vars endpoint and snapshots Testing Done: `./gradlew build -Pq` Bugs closed: AURORA-1473 Reviewed at https://reviews.apache.org/r/38280/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/26644fcc Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/26644fcc Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/26644fcc Branch: refs/heads/master Commit: 26644fcc5e018801d664dc07b3a71a0c1440501c Parents: d98bfc8 Author: Joe Smith <[email protected]> Authored: Thu Sep 17 12:31:52 2015 -0700 Committer: Zameer Manji <[email protected]> Committed: Thu Sep 17 12:31:52 2015 -0700 ---------------------------------------------------------------------- .../thrift/org/apache/aurora/gen/storage.thrift | 1 + build-support/generate-build-properties | 31 +++++++ build.gradle | 13 +++ .../common/stats/TimeSeriesRepositoryImpl.java | 33 ++++++- .../apache/aurora/common/util/BuildInfo.java | 93 ++++++++++++++++++++ .../common/util/testing/FakeBuildInfo.java | 42 +++++++++ .../stats/TimeSeriesRepositoryImplTest.java | 7 +- .../storage/backup/TemporaryStorage.java | 9 +- .../storage/log/SnapshotStoreImpl.java | 19 ++-- .../scheduler/storage/backup/RecoveryTest.java | 10 ++- .../storage/log/SnapshotStoreImplTest.java | 15 +++- 11 files changed, 261 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/api/src/main/thrift/org/apache/aurora/gen/storage.thrift ---------------------------------------------------------------------- diff --git a/api/src/main/thrift/org/apache/aurora/gen/storage.thrift b/api/src/main/thrift/org/apache/aurora/gen/storage.thrift index 670ba08..624076d 100644 --- a/api/src/main/thrift/org/apache/aurora/gen/storage.thrift +++ b/api/src/main/thrift/org/apache/aurora/gen/storage.thrift @@ -128,6 +128,7 @@ struct StoredCronJob { struct SchedulerMetadata { 1: string frameworkId 7: api.APIVersion version + 8: map<string, string> details } struct QuotaConfiguration { http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/build-support/generate-build-properties ---------------------------------------------------------------------- diff --git a/build-support/generate-build-properties b/build-support/generate-build-properties new file mode 100755 index 0000000..d9f56cd --- /dev/null +++ b/build-support/generate-build-properties @@ -0,0 +1,31 @@ +#!/bin/bash +# +# Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0 +# +# 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. +# +set -eu + +properties_file=$1 + +mkdir -p $(dirname ${properties_file}) + +cat > ${properties_file} <<EOF +time=$(date -u +'%Y-%m-%d %H:%M:%S %Z') +date=$(date +'%a %Y-%m-%d') +EOF + +if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then +cat >> ${properties_file} <<EOF +git.revision=$(git rev-parse HEAD) +git.tag=$(git describe --dirty --always) +EOF +fi http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/build.gradle ---------------------------------------------------------------------- diff --git a/build.gradle b/build.gradle index 9c78aff..5195cca 100644 --- a/build.gradle +++ b/build.gradle @@ -309,8 +309,21 @@ publishing { } } +task generateBuildProperties (type:Exec) { + def outputDir = file("${buildDir}/build-properties") + def outputFile = file("${outputDir}/build.properties") + inputs.dir rootDir + outputs.dir outputDir + doFirst { + outputDir.exists() || outputDir.mkdirs() + } + + commandLine "${projectDir}/build-support/generate-build-properties", "${outputFile}" +} + sourceSets { main { + output.dir generateBuildProperties resources { srcDir '3rdparty/javascript' } http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/commons/src/main/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImpl.java b/commons/src/main/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImpl.java index c314a0d..6b237fb 100644 --- a/commons/src/main/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImpl.java +++ b/commons/src/main/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImpl.java @@ -13,12 +13,14 @@ */ package org.apache.aurora.common.stats; +import java.util.Properties; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.logging.Logger; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -26,6 +28,7 @@ import com.google.common.cache.LoadingCache; import com.google.common.collect.EvictingQueue; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.common.primitives.Longs; import com.google.common.util.concurrent.AbstractScheduledService; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.inject.Inject; @@ -33,6 +36,7 @@ import com.google.inject.name.Named; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Time; +import org.apache.aurora.common.util.BuildInfo; import org.apache.aurora.common.util.Clock; import static com.google.common.base.Preconditions.checkNotNull; @@ -68,14 +72,17 @@ public class TimeSeriesRepositoryImpl private final StatRegistry statRegistry; private final Amount<Long, Time> samplePeriod; private final int retainedSampleLimit; + private final BuildInfo buildInfo; @Inject public TimeSeriesRepositoryImpl( StatRegistry statRegistry, @Named(SAMPLE_PERIOD) Amount<Long, Time> samplePeriod, - @Named(SAMPLE_RETENTION_PERIOD) final Amount<Long, Time> retentionPeriod) { + @Named(SAMPLE_RETENTION_PERIOD) final Amount<Long, Time> retentionPeriod, + BuildInfo buildInfo) { this.statRegistry = checkNotNull(statRegistry); this.samplePeriod = checkNotNull(samplePeriod); + this.buildInfo = checkNotNull(buildInfo); Preconditions.checkArgument(samplePeriod.getValue() > 0, "Sample period must be positive."); checkNotNull(retentionPeriod); Preconditions.checkArgument(retentionPeriod.getValue() > 0, @@ -112,6 +119,30 @@ public class TimeSeriesRepositoryImpl @Override protected void startUp() throws Exception { JvmStats.export(); + + for (String name : buildInfo.getProperties().keySet()) { + final String stringValue = buildInfo.getProperties().get(name); + LOG.info("Build Info key: " + name + " has value " + stringValue); + if (stringValue == null) { + continue; + } + final Long longValue = Longs.tryParse(stringValue); + if (longValue != null) { + Stats.exportStatic(new StatImpl<Long>(Stats.normalizeName("build." + name)) { + @Override + public Long read() { + return longValue; + } + }); + } else { + Stats.exportString(new StatImpl<String>(Stats.normalizeName("build." + name)) { + @Override + public String read() { + return stringValue; + } + }); + } + } } @Override http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/commons/src/main/java/org/apache/aurora/common/util/BuildInfo.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/util/BuildInfo.java b/commons/src/main/java/org/apache/aurora/common/util/BuildInfo.java new file mode 100644 index 0000000..4f9c384 --- /dev/null +++ b/commons/src/main/java/org/apache/aurora/common/util/BuildInfo.java @@ -0,0 +1,93 @@ +/** + * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.aurora.common.util; + +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import org.apache.aurora.common.base.MorePreconditions; + +import static java.util.Objects.requireNonNull; + +/** + * Handles loading of a build properties file, and provides keys to look up known values in the + * properties. + */ +public class BuildInfo { + + private static final Logger LOG = Logger.getLogger(BuildInfo.class.getName()); + + private static final String DEFAULT_BUILD_PROPERTIES_PATH = "build.properties"; + + private final String resourcePath; + + private Map<String, String> properties = ImmutableMap.of(); + + /** + * Creates a build info container that will use the default properties file path. + */ + public BuildInfo() { + this(DEFAULT_BUILD_PROPERTIES_PATH); + } + + /** + * Creates a build info container, reading from the given path. + * + * @param resourcePath The resource path to read build properties from. + */ + public BuildInfo(String resourcePath) { + this.resourcePath = MorePreconditions.checkNotBlank(resourcePath); + fetchProperties(); + } + + @VisibleForTesting + public BuildInfo(Map<String, String> properties) { + this.resourcePath = null; + this.properties = requireNonNull(properties); + } + + private void fetchProperties() { + LOG.info("Fetching build properties from " + resourcePath); + InputStream in = ClassLoader.getSystemResourceAsStream(resourcePath); + if (in == null) { + LOG.warning("Failed to fetch build properties from " + resourcePath); + return; + } + + try { + Properties buildProperties = new Properties(); + buildProperties.load(in); + properties = Maps.fromProperties(buildProperties); + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to load properties file " + resourcePath, e); + } + } + + /** + * Fetches the properties stored in the resource location. + * + * @return A map of the loaded properties, or an empty Map if there was a problem loading + * the specified properties resource. + */ + public Map<String, String> getProperties() { + return properties; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/commons/src/main/java/org/apache/aurora/common/util/testing/FakeBuildInfo.java ---------------------------------------------------------------------- diff --git a/commons/src/main/java/org/apache/aurora/common/util/testing/FakeBuildInfo.java b/commons/src/main/java/org/apache/aurora/common/util/testing/FakeBuildInfo.java new file mode 100644 index 0000000..edec237 --- /dev/null +++ b/commons/src/main/java/org/apache/aurora/common/util/testing/FakeBuildInfo.java @@ -0,0 +1,42 @@ +/** + * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.aurora.common.util.testing; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import org.apache.aurora.common.util.BuildInfo; + +/** + * A fixture to generate fake BuildInfo properties + */ +public class FakeBuildInfo { + + public static final String DATE = "DATE"; + public static final String GIT_REVISION = "GIT_REVISION"; + public static final String GIT_TAG = "GIT_TAG"; + + private FakeBuildInfo() { + } + + public static BuildInfo generateBuildInfo() { + Map<String, String> buildProperties = Maps.newHashMap(); + buildProperties.put(DATE, DATE); + buildProperties.put(GIT_REVISION, GIT_REVISION); + buildProperties.put(GIT_TAG, GIT_TAG); + return new BuildInfo(buildProperties); + } + +} http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/commons/src/test/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImplTest.java ---------------------------------------------------------------------- diff --git a/commons/src/test/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImplTest.java b/commons/src/test/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImplTest.java index 89c1343..6112e7c 100644 --- a/commons/src/test/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImplTest.java +++ b/commons/src/test/java/org/apache/aurora/common/stats/TimeSeriesRepositoryImplTest.java @@ -22,6 +22,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.apache.aurora.common.util.testing.FakeBuildInfo.generateBuildInfo; import static org.easymock.EasyMock.createStrictControl; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; @@ -42,7 +43,11 @@ public class TimeSeriesRepositoryImplTest extends EasyMockTest { public void setUp() { control = createStrictControl(); statRegistry = control.createMock(StatRegistry.class); - repo = new TimeSeriesRepositoryImpl(statRegistry, SAMPLE_PERIOD, RETENTION_PERIOD); + repo = new TimeSeriesRepositoryImpl( + statRegistry, + SAMPLE_PERIOD, + RETENTION_PERIOD, + generateBuildInfo()); clock = new FakeClock(); } http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/src/main/java/org/apache/aurora/scheduler/storage/backup/TemporaryStorage.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/storage/backup/TemporaryStorage.java b/src/main/java/org/apache/aurora/scheduler/storage/backup/TemporaryStorage.java index d76596c..6af059d 100644 --- a/src/main/java/org/apache/aurora/scheduler/storage/backup/TemporaryStorage.java +++ b/src/main/java/org/apache/aurora/scheduler/storage/backup/TemporaryStorage.java @@ -18,6 +18,7 @@ import java.util.Set; import com.google.common.base.Function; import com.google.common.collect.FluentIterable; +import org.apache.aurora.common.util.BuildInfo; import org.apache.aurora.common.util.testing.FakeClock; import org.apache.aurora.gen.storage.Snapshot; import org.apache.aurora.scheduler.base.Query; @@ -32,6 +33,8 @@ import org.apache.aurora.scheduler.storage.db.DbUtil; import org.apache.aurora.scheduler.storage.entities.IScheduledTask; import org.apache.aurora.scheduler.storage.log.SnapshotStoreImpl; +import static org.apache.aurora.common.util.testing.FakeBuildInfo.generateBuildInfo; + /** * A short-lived in-memory storage system that can be converted to a {@link Snapshot}. */ @@ -67,9 +70,13 @@ interface TemporaryStorage { @Override public TemporaryStorage apply(Snapshot snapshot) { final Storage storage = DbUtil.createFlaggedStorage(); + final BuildInfo buildInfo = generateBuildInfo(); FakeClock clock = new FakeClock(); clock.setNowMillis(snapshot.getTimestamp()); - final SnapshotStore<Snapshot> snapshotStore = new SnapshotStoreImpl(clock, storage); + final SnapshotStore<Snapshot> snapshotStore = new SnapshotStoreImpl( + buildInfo, + clock, + storage); snapshotStore.applySnapshot(snapshot); return new TemporaryStorage() { http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/src/main/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImpl.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImpl.java b/src/main/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImpl.java index 50838de..ed1fffe 100644 --- a/src/main/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImpl.java +++ b/src/main/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImpl.java @@ -16,13 +16,13 @@ package org.apache.aurora.scheduler.storage.log; import java.util.Arrays; import java.util.Map; import java.util.logging.Logger; - import javax.inject.Inject; import com.google.common.base.Optional; import com.google.common.collect.ImmutableSet; import org.apache.aurora.common.inject.TimedInterceptor.Timed; +import org.apache.aurora.common.util.BuildInfo; import org.apache.aurora.common.util.Clock; import org.apache.aurora.gen.HostAttributes; import org.apache.aurora.gen.JobInstanceUpdateEvent; @@ -152,10 +152,7 @@ public class SnapshotStoreImpl implements SnapshotStore<Snapshot> { new SnapshotField() { @Override public void saveToSnapshot(StoreProvider store, Snapshot snapshot) { - snapshot.setSchedulerMetadata( - new SchedulerMetadata() - .setFrameworkId(store.getSchedulerStore().fetchFrameworkId().orNull()) - .setVersion(CURRENT_API_VERSION)); + // SchedulerMetadata is updated outside of the static list of SnapshotFields } @Override @@ -233,11 +230,13 @@ public class SnapshotStoreImpl implements SnapshotStore<Snapshot> { } ); + private final BuildInfo buildInfo; private final Clock clock; private final Storage storage; @Inject - public SnapshotStoreImpl(Clock clock, @Volatile Storage storage) { + public SnapshotStoreImpl(BuildInfo buildInfo, Clock clock, @Volatile Storage storage) { + this.buildInfo = requireNonNull(buildInfo); this.clock = requireNonNull(clock); this.storage = requireNonNull(storage); } @@ -258,6 +257,14 @@ public class SnapshotStoreImpl implements SnapshotStore<Snapshot> { for (SnapshotField field : SNAPSHOT_FIELDS) { field.saveToSnapshot(storeProvider, snapshot); } + + SchedulerMetadata metadata = new SchedulerMetadata() + .setFrameworkId(storeProvider.getSchedulerStore().fetchFrameworkId().orNull()) + .setVersion(CURRENT_API_VERSION); + + metadata.setDetails(buildInfo.getProperties()); + + snapshot.setSchedulerMetadata(metadata); snapshot.setTimestamp(timestamp); return snapshot; } http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/src/test/java/org/apache/aurora/scheduler/storage/backup/RecoveryTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/storage/backup/RecoveryTest.java b/src/test/java/org/apache/aurora/scheduler/storage/backup/RecoveryTest.java index cc9c066..1e4e625 100644 --- a/src/test/java/org/apache/aurora/scheduler/storage/backup/RecoveryTest.java +++ b/src/test/java/org/apache/aurora/scheduler/storage/backup/RecoveryTest.java @@ -23,6 +23,7 @@ import org.apache.aurora.common.base.Command; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Time; import org.apache.aurora.common.testing.easymock.EasyMockTest; +import org.apache.aurora.common.util.testing.FakeBuildInfo; import org.apache.aurora.common.util.testing.FakeClock; import org.apache.aurora.gen.storage.SchedulerMetadata; import org.apache.aurora.gen.storage.Snapshot; @@ -152,10 +153,17 @@ public class RecoveryTest extends EasyMockTest { } private static Snapshot makeSnapshot(IScheduledTask... tasks) { + SchedulerMetadata metadata = new SchedulerMetadata() + .setVersion(CURRENT_API_VERSION); + metadata.setDetails(com.google.common.collect.Maps.newHashMap()); + metadata.getDetails().put(FakeBuildInfo.DATE, FakeBuildInfo.DATE); + metadata.getDetails().put(FakeBuildInfo.GIT_REVISION, FakeBuildInfo.GIT_REVISION); + metadata.getDetails().put(FakeBuildInfo.GIT_TAG, FakeBuildInfo.GIT_TAG); + return new Snapshot() .setHostAttributes(ImmutableSet.of()) .setCronJobs(ImmutableSet.of()) - .setSchedulerMetadata(new SchedulerMetadata().setVersion(CURRENT_API_VERSION)) + .setSchedulerMetadata(metadata) .setQuotaConfigurations(ImmutableSet.of()) .setTasks(IScheduledTask.toBuildersSet(ImmutableSet.copyOf(tasks))) .setLocks(ImmutableSet.of()) http://git-wip-us.apache.org/repos/asf/aurora/blob/26644fcc/src/test/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImplTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImplTest.java b/src/test/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImplTest.java index 6e032a6..02400f0 100644 --- a/src/test/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImplTest.java +++ b/src/test/java/org/apache/aurora/scheduler/storage/log/SnapshotStoreImplTest.java @@ -20,8 +20,10 @@ 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.common.collect.Maps; import org.apache.aurora.common.testing.easymock.EasyMockTest; +import org.apache.aurora.common.util.testing.FakeBuildInfo; import org.apache.aurora.common.util.testing.FakeClock; import org.apache.aurora.gen.Attribute; import org.apache.aurora.gen.HostAttributes; @@ -58,6 +60,7 @@ import org.apache.aurora.scheduler.storage.testing.StorageTestUtil; import org.junit.Before; import org.junit.Test; +import static org.apache.aurora.common.util.testing.FakeBuildInfo.generateBuildInfo; import static org.apache.aurora.gen.apiConstants.CURRENT_API_VERSION; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; @@ -74,7 +77,10 @@ public class SnapshotStoreImplTest extends EasyMockTest { FakeClock clock = new FakeClock(); clock.setNowMillis(NOW); storageUtil = new StorageTestUtil(this); - snapshotStore = new SnapshotStoreImpl(clock, storageUtil.storage); + snapshotStore = new SnapshotStoreImpl( + generateBuildInfo(), + clock, + storageUtil.storage); } private static IJobUpdateKey makeKey(String id) { @@ -107,6 +113,10 @@ public class SnapshotStoreImplTest extends EasyMockTest { SchedulerMetadata metadata = new SchedulerMetadata() .setFrameworkId(frameworkId) .setVersion(CURRENT_API_VERSION); + metadata.setDetails(Maps.newHashMap()); + metadata.getDetails().put(FakeBuildInfo.DATE, FakeBuildInfo.DATE); + metadata.getDetails().put(FakeBuildInfo.GIT_REVISION, FakeBuildInfo.GIT_REVISION); + metadata.getDetails().put(FakeBuildInfo.GIT_TAG, FakeBuildInfo.GIT_TAG); IJobUpdateKey updateId1 = makeKey("updateId1"); IJobUpdateKey updateId2 = makeKey("updateId2"); IJobUpdateDetails updateDetails1 = IJobUpdateDetails.build(new JobUpdateDetails() @@ -171,7 +181,8 @@ public class SnapshotStoreImplTest extends EasyMockTest { new StoredJobUpdateDetails(updateDetails1.newBuilder(), lockToken), new StoredJobUpdateDetails(updateDetails2.newBuilder(), null))); - assertEquals(expected, snapshotStore.createSnapshot()); + Snapshot snapshot = snapshotStore.createSnapshot(); + assertEquals(expected, snapshot); snapshotStore.applySnapshot(expected); }
