Create system for job migrations.
This commit is contained in:
parent
9580bb0a38
commit
af42d5b671
12 changed files with 388 additions and 3 deletions
|
@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
|||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider;
|
||||
import org.thoughtcrime.securesms.gcm.FcmJobService;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigrator;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||
import org.thoughtcrime.securesms.jobs.FastJobStorage;
|
||||
|
@ -222,6 +223,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
|
|||
.setConstraintFactories(JobManagerFactories.getConstraintFactories(this))
|
||||
.setConstraintObservers(JobManagerFactories.getConstraintObservers(this))
|
||||
.setJobStorage(new FastJobStorage(DatabaseFactory.getJobDatabase(this)))
|
||||
.setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(this), 1, JobManagerFactories.getJobMigrations()))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,39 @@ public class JobDatabase extends Database {
|
|||
databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, null, null);
|
||||
}
|
||||
|
||||
public synchronized void updateJobs(@NonNull List<JobSpec> jobs) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
|
||||
try {
|
||||
for (JobSpec job : jobs) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Jobs.JOB_SPEC_ID, job.getId());
|
||||
values.put(Jobs.FACTORY_KEY, job.getFactoryKey());
|
||||
values.put(Jobs.QUEUE_KEY, job.getQueueKey());
|
||||
values.put(Jobs.CREATE_TIME, job.getCreateTime());
|
||||
values.put(Jobs.NEXT_RUN_ATTEMPT_TIME, job.getNextRunAttemptTime());
|
||||
values.put(Jobs.RUN_ATTEMPT, job.getRunAttempt());
|
||||
values.put(Jobs.MAX_ATTEMPTS, job.getMaxAttempts());
|
||||
values.put(Jobs.MAX_BACKOFF, job.getMaxBackoff());
|
||||
values.put(Jobs.MAX_INSTANCES, job.getMaxInstances());
|
||||
values.put(Jobs.LIFESPAN, job.getLifespan());
|
||||
values.put(Jobs.SERIALIZED_DATA, job.getSerializedData());
|
||||
values.put(Jobs.IS_RUNNING, job.isRunning() ? 1 : 0);
|
||||
|
||||
String query = Jobs.JOB_SPEC_ID + " = ?";
|
||||
String[] args = new String[]{ job.getId() };
|
||||
|
||||
db.update(Jobs.TABLE_NAME, values, query, args);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void deleteJobs(@NonNull List<String> jobIds) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ class JobController {
|
|||
|
||||
@WorkerThread
|
||||
synchronized void init() {
|
||||
jobStorage.init();
|
||||
jobStorage.updateAllJobsToBePending();
|
||||
notifyAll();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.app.Application;
|
|||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.DefaultExecutorFactory;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
||||
|
@ -11,6 +12,7 @@ import org.thoughtcrime.securesms.jobmanager.workmanager.WorkManagerMigrator;
|
|||
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.Debouncer;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -58,6 +60,12 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
WorkManagerMigrator.migrate(application, configuration.getJobStorage(), configuration.getDataSerializer());
|
||||
}
|
||||
|
||||
JobStorage jobStorage = configuration.getJobStorage();
|
||||
jobStorage.init();
|
||||
|
||||
int latestVersion = configuration.getJobMigrator().migrate(jobStorage, configuration.getDataSerializer());
|
||||
TextSecurePreferences.setJobManagerVersion(application, latestVersion);
|
||||
|
||||
jobController.init();
|
||||
|
||||
for (ConstraintObserver constraintObserver : configuration.getConstraintObservers()) {
|
||||
|
@ -214,6 +222,7 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
private final List<ConstraintObserver> constraintObservers;
|
||||
private final Data.Serializer dataSerializer;
|
||||
private final JobStorage jobStorage;
|
||||
private final JobMigrator jobMigrator;
|
||||
|
||||
private Configuration(int jobThreadCount,
|
||||
@NonNull ExecutorFactory executorFactory,
|
||||
|
@ -221,7 +230,8 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
@NonNull ConstraintInstantiator constraintInstantiator,
|
||||
@NonNull List<ConstraintObserver> constraintObservers,
|
||||
@NonNull Data.Serializer dataSerializer,
|
||||
@NonNull JobStorage jobStorage)
|
||||
@NonNull JobStorage jobStorage,
|
||||
@NonNull JobMigrator jobMigrator)
|
||||
{
|
||||
this.executorFactory = executorFactory;
|
||||
this.jobThreadCount = jobThreadCount;
|
||||
|
@ -230,6 +240,7 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
this.constraintObservers = constraintObservers;
|
||||
this.dataSerializer = dataSerializer;
|
||||
this.jobStorage = jobStorage;
|
||||
this.jobMigrator = jobMigrator;
|
||||
}
|
||||
|
||||
int getJobThreadCount() {
|
||||
|
@ -261,6 +272,10 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
return jobStorage;
|
||||
}
|
||||
|
||||
@NonNull JobMigrator getJobMigrator() {
|
||||
return jobMigrator;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private ExecutorFactory executorFactory = new DefaultExecutorFactory();
|
||||
|
@ -270,6 +285,7 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
private List<ConstraintObserver> constraintObservers = new ArrayList<>();
|
||||
private Data.Serializer dataSerializer = new JsonDataSerializer();
|
||||
private JobStorage jobStorage = null;
|
||||
private JobMigrator jobMigrator = null;
|
||||
|
||||
public @NonNull Builder setJobThreadCount(int jobThreadCount) {
|
||||
this.jobThreadCount = jobThreadCount;
|
||||
|
@ -306,6 +322,11 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder setJobMigrator(@NonNull JobMigrator jobMigrator) {
|
||||
this.jobMigrator = jobMigrator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Configuration build() {
|
||||
return new Configuration(jobThreadCount,
|
||||
executorFactory,
|
||||
|
@ -313,7 +334,8 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
new ConstraintInstantiator(constraintFactories),
|
||||
new ArrayList<>(constraintObservers),
|
||||
dataSerializer,
|
||||
jobStorage);
|
||||
jobStorage,
|
||||
jobMigrator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
62
src/org/thoughtcrime/securesms/jobmanager/JobMigration.java
Normal file
62
src/org/thoughtcrime/securesms/jobmanager/JobMigration.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package org.thoughtcrime.securesms.jobmanager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Create a subclass of this to perform a migration on persisted {@link Job}s. A migration targets
|
||||
* a specific end version, and the assumption is that it can migrate jobs to that end version from
|
||||
* the previous version. The class will be provided a bundle of job data for each persisted job and
|
||||
* give back an updated version (if applicable).
|
||||
*/
|
||||
public abstract class JobMigration {
|
||||
|
||||
private final int endVersion;
|
||||
|
||||
protected JobMigration(int endVersion) {
|
||||
this.endVersion = endVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a bundle of job data, return a bundle of job data that should be used in place of it.
|
||||
* You may obviously return the same object if you don't wish to change it.
|
||||
*/
|
||||
protected abstract @NonNull JobData migrate(@NonNull JobData jobData);
|
||||
|
||||
int getEndVersion() {
|
||||
return endVersion;
|
||||
}
|
||||
|
||||
protected static class JobData {
|
||||
|
||||
private final String factoryKey;
|
||||
private final String queueKey;
|
||||
private final Data data;
|
||||
|
||||
JobData(@NonNull String factoryKey, @Nullable String queueKey, @NonNull Data data) {
|
||||
this.factoryKey = factoryKey;
|
||||
this.queueKey = queueKey;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
protected @NonNull JobData withQueueKey(@Nullable String newQueueKey) {
|
||||
return new JobData(factoryKey, newQueueKey, data);
|
||||
}
|
||||
|
||||
protected @NonNull JobData withData(@NonNull Data newData) {
|
||||
return new JobData(factoryKey, queueKey, newData);
|
||||
}
|
||||
|
||||
public @NonNull String getFactoryKey() {
|
||||
return factoryKey;
|
||||
}
|
||||
|
||||
public @Nullable String getQueueKey() {
|
||||
return queueKey;
|
||||
}
|
||||
|
||||
public @NonNull Data getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
88
src/org/thoughtcrime/securesms/jobmanager/JobMigrator.java
Normal file
88
src/org/thoughtcrime/securesms/jobmanager/JobMigrator.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package org.thoughtcrime.securesms.jobmanager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressLint("UseSparseArrays")
|
||||
public class JobMigrator {
|
||||
|
||||
private static final String TAG = Log.tag(JobMigrator.class);
|
||||
|
||||
private final int lastSeenVersion;
|
||||
private final int currentVersion;
|
||||
private final Map<Integer, JobMigration> migrations;
|
||||
|
||||
public JobMigrator(int lastSeenVersion, int currentVersion, @NonNull List<JobMigration> migrations) {
|
||||
this.lastSeenVersion = lastSeenVersion;
|
||||
this.currentVersion = currentVersion;
|
||||
this.migrations = new HashMap<>();
|
||||
|
||||
if (migrations.size() != currentVersion - 1) {
|
||||
throw new AssertionError("You must have a migration for every version!");
|
||||
}
|
||||
|
||||
for (int i = 0; i < migrations.size(); i++) {
|
||||
JobMigration migration = migrations.get(i);
|
||||
|
||||
if (migration.getEndVersion() != i + 2) {
|
||||
throw new AssertionError("Missing migration for version " + (i + 2) + "!");
|
||||
}
|
||||
|
||||
this.migrations.put(migration.getEndVersion(), migrations.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The version that has been migrated to.
|
||||
*/
|
||||
int migrate(@NonNull JobStorage jobStorage, @NonNull Data.Serializer dataSerializer) {
|
||||
List<JobSpec> jobSpecs = jobStorage.getAllJobSpecs();
|
||||
|
||||
for (int i = lastSeenVersion; i < currentVersion; i++) {
|
||||
Log.i(TAG, "Migrating from " + i + " to " + (i + 1));
|
||||
|
||||
ListIterator<JobSpec> iter = jobSpecs.listIterator();
|
||||
JobMigration migration = migrations.get(i + 1);
|
||||
|
||||
assert migration != null;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
JobSpec jobSpec = iter.next();
|
||||
Data data = dataSerializer.deserialize(jobSpec.getSerializedData());
|
||||
JobData originalJobData = new JobData(jobSpec.getFactoryKey(), jobSpec.getQueueKey(), data);
|
||||
JobData updatedJobData = migration.migrate(originalJobData);
|
||||
JobSpec updatedJobSpec = new JobSpec(jobSpec.getId(),
|
||||
jobSpec.getFactoryKey(),
|
||||
updatedJobData.getQueueKey(),
|
||||
jobSpec.getCreateTime(),
|
||||
jobSpec.getNextRunAttemptTime(),
|
||||
jobSpec.getRunAttempt(),
|
||||
jobSpec.getMaxAttempts(),
|
||||
jobSpec.getMaxBackoff(),
|
||||
jobSpec.getLifespan(),
|
||||
jobSpec.getMaxInstances(),
|
||||
dataSerializer.serialize(updatedJobData.getData()),
|
||||
jobSpec.isRunning());
|
||||
|
||||
iter.set(updatedJobSpec);
|
||||
}
|
||||
}
|
||||
|
||||
jobStorage.updateJobs(jobSpecs);
|
||||
|
||||
return currentVersion;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,9 @@ public interface JobStorage {
|
|||
@WorkerThread
|
||||
void updateAllJobsToBePending();
|
||||
|
||||
@WorkerThread
|
||||
void updateJobs(@NonNull List<JobSpec> jobSpecs);
|
||||
|
||||
@WorkerThread
|
||||
void deleteJob(@NonNull String id);
|
||||
|
||||
|
|
|
@ -212,6 +212,23 @@ public class FastJobStorage implements JobStorage {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateJobs(@NonNull List<JobSpec> jobSpecs) {
|
||||
jobDatabase.updateJobs(jobSpecs);
|
||||
|
||||
Map<String, JobSpec> updates = Stream.of(jobSpecs).collect(Collectors.toMap(JobSpec::getId));
|
||||
ListIterator<JobSpec> iter = jobs.listIterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
JobSpec existing = iter.next();
|
||||
JobSpec update = updates.get(existing.getId());
|
||||
|
||||
if (update != null) {
|
||||
iter.set(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void deleteJob(@NonNull String jobId) {
|
||||
deleteJobs(Collections.singletonList(jobId));
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
|||
import org.thoughtcrime.securesms.jobmanager.Constraint;
|
||||
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraint;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
|
@ -18,6 +19,7 @@ import org.thoughtcrime.securesms.migrations.LegacyMigrationJob;
|
|||
import org.thoughtcrime.securesms.migrations.MigrationCompleteJob;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -102,4 +104,8 @@ public final class JobManagerFactories {
|
|||
new NetworkConstraintObserver(application),
|
||||
new SqlCipherMigrationConstraintObserver());
|
||||
}
|
||||
|
||||
public static List<JobMigration> getJobMigrations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,8 @@ public class TextSecurePreferences {
|
|||
|
||||
private static final String SEEN_CAMERA_FIRST_TOOLTIP = "pref_seen_camera_first_tooltip";
|
||||
|
||||
private static final String JOB_MANAGER_VERSION = "pref_job_manager_version";
|
||||
|
||||
public static boolean isScreenLockEnabled(@NonNull Context context) {
|
||||
return getBooleanPreference(context, SCREEN_LOCK, false);
|
||||
}
|
||||
|
@ -1118,6 +1120,14 @@ public class TextSecurePreferences {
|
|||
return getBooleanPreference(context, SEEN_CAMERA_FIRST_TOOLTIP, false);
|
||||
}
|
||||
|
||||
public static void setJobManagerVersion(Context context, int version) {
|
||||
setIntegerPrefrence(context, JOB_MANAGER_VERSION, version);
|
||||
}
|
||||
|
||||
public static int getJobManagerVersion(Context contex) {
|
||||
return getIntegerPreference(contex, JOB_MANAGER_VERSION, 1);
|
||||
}
|
||||
|
||||
public static void setBooleanPreference(Context context, String key, boolean value) {
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(key, value).apply();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package org.thoughtcrime.securesms.jobmanager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class JobMigratorTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
Log.initialize(mock(Log.Logger.class));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void JobMigrator_crashWhenTooFewMigrations() {
|
||||
new JobMigrator(1, 2, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void JobMigrator_crashWhenTooManyMigrations() {
|
||||
new JobMigrator(1, 2, Arrays.asList(new EmptyMigration(2), new EmptyMigration(3)));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void JobMigrator_crashWhenSkippingMigrations() {
|
||||
new JobMigrator(1, 3, Arrays.asList(new EmptyMigration(2), new EmptyMigration(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void JobMigrator_properInitialization() {
|
||||
new JobMigrator(1, 3, Arrays.asList(new EmptyMigration(2), new EmptyMigration(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_callsAppropriateMigrations_fullSet() {
|
||||
JobMigration migration1 = spy(new EmptyMigration(2));
|
||||
JobMigration migration2 = spy(new EmptyMigration(3));
|
||||
|
||||
JobMigrator subject = new JobMigrator(1, 3, Arrays.asList(migration1, migration2));
|
||||
int version = subject.migrate(simpleJobStorage(), mock(Data.Serializer.class));
|
||||
|
||||
assertEquals(3, version);
|
||||
verify(migration1).migrate(any());
|
||||
verify(migration2).migrate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_callsAppropriateMigrations_subset() {
|
||||
JobMigration migration1 = spy(new EmptyMigration(2));
|
||||
JobMigration migration2 = spy(new EmptyMigration(3));
|
||||
|
||||
JobMigrator subject = new JobMigrator(2, 3, Arrays.asList(migration1, migration2));
|
||||
int version = subject.migrate(simpleJobStorage(), mock(Data.Serializer.class));
|
||||
|
||||
assertEquals(3, version);
|
||||
verify(migration1, never()).migrate(any());
|
||||
verify(migration2).migrate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_callsAppropriateMigrations_none() {
|
||||
JobMigration migration1 = spy(new EmptyMigration(2));
|
||||
JobMigration migration2 = spy(new EmptyMigration(3));
|
||||
|
||||
JobMigrator subject = new JobMigrator(3, 3, Arrays.asList(migration1, migration2));
|
||||
int version = subject.migrate(simpleJobStorage(), mock(Data.Serializer.class));
|
||||
|
||||
assertEquals(3, version);
|
||||
verify(migration1, never()).migrate(any());
|
||||
verify(migration2, never()).migrate(any());
|
||||
}
|
||||
|
||||
private static JobStorage simpleJobStorage() {
|
||||
JobStorage jobStorage = mock(JobStorage.class);
|
||||
when(jobStorage.getAllJobSpecs()).thenReturn(new ArrayList<>(Collections.singletonList(new JobSpec("1", "f1", null, 1, 1, 1, 1, 1, 1, 1, "", false))));
|
||||
return jobStorage;
|
||||
}
|
||||
|
||||
private static class EmptyMigration extends JobMigration {
|
||||
|
||||
protected EmptyMigration(int endVersion) {
|
||||
super(endVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull JobData migrate(@NonNull JobData jobData) {
|
||||
return jobData;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,6 +101,43 @@ public class FastJobStorageTest {
|
|||
assertFalse(subject.getJobSpec("2").isRunning());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateJobs_writesToDatabase() {
|
||||
JobDatabase database = noopDatabase();
|
||||
FastJobStorage subject = new FastJobStorage(database);
|
||||
List<JobSpec> jobs = Collections.emptyList();
|
||||
|
||||
subject.updateJobs(jobs);
|
||||
|
||||
verify(database).updateJobs(jobs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateJobs_updatesAllFields() {
|
||||
|
||||
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, false),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, false),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
FullSpec fullSpec3 = new FullSpec(new JobSpec("3", "f3", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, false),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
|
||||
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2, fullSpec3)));
|
||||
|
||||
JobSpec update1 = new JobSpec("1", "g1", "q1", 2, 2, 2, 2, 2, 2, 2, "abc", true);
|
||||
JobSpec update2 = new JobSpec("2", "g2", "q2", 3, 3, 3, 3, 3, 3, 3, "def", true);
|
||||
|
||||
subject.init();
|
||||
subject.updateJobs(Arrays.asList(update1, update2));
|
||||
|
||||
assertEquals(update1, subject.getJobSpec("1"));
|
||||
assertEquals(update2, subject.getJobSpec("2"));
|
||||
assertEquals(fullSpec3.getJobSpec(), subject.getJobSpec("3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateJobRunningState_writesToDatabase() {
|
||||
JobDatabase database = noopDatabase();
|
||||
|
|
Loading…
Add table
Reference in a new issue