You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by wf...@apache.org on 2014/11/20 00:22:32 UTC
incubator-aurora git commit: Add more test coverage to
SchedulerThriftInterface.
Repository: incubator-aurora
Updated Branches:
refs/heads/master 2aa0026fd -> 4e52d00b8
Add more test coverage to SchedulerThriftInterface.
Bugs closed: AURORA-937
Reviewed at https://reviews.apache.org/r/28026/
Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/4e52d00b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/4e52d00b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/4e52d00b
Branch: refs/heads/master
Commit: 4e52d00b881a346b50dae54b2b3f71f9d3f08d8b
Parents: 2aa0026
Author: Bill Farner <wf...@apache.org>
Authored: Wed Nov 19 15:13:28 2014 -0800
Committer: Bill Farner <wf...@apache.org>
Committed: Wed Nov 19 15:13:28 2014 -0800
----------------------------------------------------------------------
.../apache/aurora/auth/SessionValidator.java | 4 -
.../scheduler/storage/backup/Recovery.java | 6 +-
.../thrift/SchedulerThriftInterface.java | 77 ++----
.../apache/aurora/scheduler/thrift/Util.java | 11 +
.../aurora/scheduler/thrift/aop/AopModule.java | 7 +-
.../thrift/SchedulerThriftInterfaceTest.java | 277 +++++++++++++++++--
6 files changed, 300 insertions(+), 82 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/4e52d00b/src/main/java/org/apache/aurora/auth/SessionValidator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/auth/SessionValidator.java b/src/main/java/org/apache/aurora/auth/SessionValidator.java
index eeebb78..b688a0f 100644
--- a/src/main/java/org/apache/aurora/auth/SessionValidator.java
+++ b/src/main/java/org/apache/aurora/auth/SessionValidator.java
@@ -64,9 +64,5 @@ public interface SessionValidator {
public AuthFailedException(String msg) {
super(msg);
}
-
- public AuthFailedException(String msg, Throwable cause) {
- super(msg, cause);
- }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/4e52d00b/src/main/java/org/apache/aurora/scheduler/storage/backup/Recovery.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/storage/backup/Recovery.java b/src/main/java/org/apache/aurora/scheduler/storage/backup/Recovery.java
index 4744dc9..38764e5 100644
--- a/src/main/java/org/apache/aurora/scheduler/storage/backup/Recovery.java
+++ b/src/main/java/org/apache/aurora/scheduler/storage/backup/Recovery.java
@@ -93,12 +93,12 @@ public interface Recovery {
* Thrown when a recovery operation could not be completed due to internal errors or improper
* invocation order.
*/
- class RecoveryException extends Exception {
- RecoveryException(String message) {
+ class RecoveryException extends RuntimeException {
+ public RecoveryException(String message) {
super(message);
}
- RecoveryException(String message, Throwable cause) {
+ public RecoveryException(String message, Throwable cause) {
super(message, cause);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/4e52d00b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
index 4b65a2c..b66b916 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterface.java
@@ -20,7 +20,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@@ -35,7 +34,6 @@ import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
-import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
@@ -142,7 +140,6 @@ import org.apache.aurora.scheduler.storage.Storage.NonVolatileStorage;
import org.apache.aurora.scheduler.storage.Storage.StoreProvider;
import org.apache.aurora.scheduler.storage.Storage.Work;
import org.apache.aurora.scheduler.storage.backup.Recovery;
-import org.apache.aurora.scheduler.storage.backup.Recovery.RecoveryException;
import org.apache.aurora.scheduler.storage.backup.StorageBackup;
import org.apache.aurora.scheduler.storage.entities.IAssignedTask;
import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
@@ -176,7 +173,6 @@ import static com.twitter.common.base.MorePreconditions.checkNotBlank;
import static org.apache.aurora.auth.SessionValidator.SessionContext;
import static org.apache.aurora.gen.ResponseCode.AUTH_FAILED;
-import static org.apache.aurora.gen.ResponseCode.ERROR;
import static org.apache.aurora.gen.ResponseCode.INVALID_REQUEST;
import static org.apache.aurora.gen.ResponseCode.LOCK_ERROR;
import static org.apache.aurora.gen.ResponseCode.OK;
@@ -987,45 +983,26 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
@Override
public Response stageRecovery(String backupId, SessionKey session) {
- try {
- recovery.stage(backupId);
- return okEmptyResponse();
- } catch (RecoveryException e) {
- LOG.log(Level.WARNING, "Failed to stage recovery: " + e, e);
- return errorResponse(ERROR, e);
- }
+ recovery.stage(backupId);
+ return okEmptyResponse();
}
@Override
public Response queryRecovery(TaskQuery query, SessionKey session) {
- try {
- return okResponse(Result.queryRecoveryResult(new QueryRecoveryResult()
- .setTasks(IScheduledTask.toBuildersSet(recovery.query(Query.arbitrary(query))))));
- } catch (RecoveryException e) {
- LOG.log(Level.WARNING, "Failed to query recovery: " + e, e);
- return errorResponse(ERROR, e);
- }
+ return okResponse(Result.queryRecoveryResult(new QueryRecoveryResult()
+ .setTasks(IScheduledTask.toBuildersSet(recovery.query(Query.arbitrary(query))))));
}
@Override
public Response deleteRecoveryTasks(TaskQuery query, SessionKey session) {
- try {
- recovery.deleteTasks(Query.arbitrary(query));
- return okEmptyResponse();
- } catch (RecoveryException e) {
- LOG.log(Level.WARNING, "Failed to delete recovery tasks: " + e, e);
- return errorResponse(ERROR, e);
- }
+ recovery.deleteTasks(Query.arbitrary(query));
+ return okEmptyResponse();
}
@Override
public Response commitRecovery(SessionKey session) {
- try {
- recovery.commit();
- return okEmptyResponse();
- } catch (RecoveryException e) {
- return errorResponse(ERROR, e);
- }
+ recovery.commit();
+ return okEmptyResponse();
}
@Override
@@ -1036,34 +1013,25 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
@Override
public Response snapshot(SessionKey session) {
- try {
- storage.snapshot();
- return okEmptyResponse();
- } catch (Storage.StorageException e) {
- LOG.log(Level.WARNING, "Requested snapshot failed.", e);
- return errorResponse(ERROR, e);
- }
+ storage.snapshot();
+ return okEmptyResponse();
}
private static Multimap<String, IJobConfiguration> jobsByKey(JobStore jobStore, IJobKey jobKey) {
ImmutableMultimap.Builder<String, IJobConfiguration> matches = ImmutableMultimap.builder();
for (String managerId : jobStore.fetchManagerIds()) {
- for (IJobConfiguration job : jobStore.fetchJobs(managerId)) {
- if (job.getKey().equals(jobKey)) {
- matches.put(managerId, job);
- }
+ Optional<IJobConfiguration> job = jobStore.fetchJob(managerId, jobKey);
+ if (job.isPresent()) {
+ matches.put(managerId, job.get());
}
}
return matches.build();
}
@Override
- public Response rewriteConfigs(
- final RewriteConfigsRequest request,
- SessionKey session) {
-
+ public Response rewriteConfigs(final RewriteConfigsRequest request, SessionKey session) {
if (request.getRewriteCommandsSize() == 0) {
- return addMessage(Util.emptyResponse(), ERROR, "No rewrite commands provided.");
+ return addMessage(Util.emptyResponse(), INVALID_REQUEST, "No rewrite commands provided.");
}
return storage.write(new MutateWork.Quiet<Response>() {
@@ -1101,7 +1069,7 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
} catch (TaskDescriptionException e) {
// We could add an error here, but this is probably a hint of something wrong in
// the client that's causing a bad configuration to be applied.
- throw Throwables.propagate(e);
+ throw new RuntimeException(e);
}
if (existingJob.getKey().equals(rewrittenJob.getKey())) {
@@ -1454,10 +1422,6 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
JobDiff.asMap(request.getTaskConfig(), request.getInstanceCount()),
settings.getUpdateOnlyTheseInstances());
- if (diff.isNoop()) {
- return addMessage(emptyResponse(), OK, NOOP_JOB_UPDATE_MESSAGE);
- }
-
Set<Integer> invalidScope = diff.getOutOfScopeInstances(
Numbers.rangesToInstanceIds(settings.getUpdateOnlyTheseInstances()));
if (!invalidScope.isEmpty()) {
@@ -1466,6 +1430,10 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
+ invalidScope);
}
+ if (diff.isNoop()) {
+ return addMessage(emptyResponse(), OK, NOOP_JOB_UPDATE_MESSAGE);
+ }
+
JobUpdateInstructions instructions = new JobUpdateInstructions()
.setSettings(settings.newBuilder())
.setInitialState(buildInitialState(diff.getReplacedInstances()));
@@ -1557,9 +1525,12 @@ class SchedulerThriftInterface implements AuroraAdmin.Iface {
});
}
+ @VisibleForTesting
+ static final String NOT_IMPLEMENTED_MESSAGE = "Not implemented";
+
@Override
public Response pulseJobUpdate(String updateId, SessionKey session) {
- throw new UnsupportedOperationException("Not implemented");
+ throw new UnsupportedOperationException(NOT_IMPLEMENTED_MESSAGE);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/4e52d00b/src/main/java/org/apache/aurora/scheduler/thrift/Util.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/Util.java b/src/main/java/org/apache/aurora/scheduler/thrift/Util.java
index 18e2bdf..d879db4 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/Util.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/Util.java
@@ -21,6 +21,8 @@ import org.apache.aurora.gen.Response;
import org.apache.aurora.gen.ResponseCode;
import org.apache.aurora.gen.ResponseDetail;
+import static org.apache.aurora.gen.ResponseCode.OK;
+
/**
* Utility class for constructing responses to API calls.
*/
@@ -85,4 +87,13 @@ public final class Util {
response.addToDetails(new ResponseDetail(message));
return response;
}
+
+ /**
+ * Creates an OK response that has no result entity.
+ *
+ * @return Ok response with an empty result.
+ */
+ public static Response okEmptyResponse() {
+ return emptyResponse().setResponseCode(OK);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/4e52d00b/src/main/java/org/apache/aurora/scheduler/thrift/aop/AopModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/aop/AopModule.java b/src/main/java/org/apache/aurora/scheduler/thrift/aop/AopModule.java
index dca855c..83b8f39 100644
--- a/src/main/java/org/apache/aurora/scheduler/thrift/aop/AopModule.java
+++ b/src/main/java/org/apache/aurora/scheduler/thrift/aop/AopModule.java
@@ -86,9 +86,13 @@ public class AopModule extends AbstractModule {
requireBinding(CapabilityValidator.class);
// Layer ordering:
- // Log -> CapabilityValidator -> FeatureToggle -> StatsExporter -> APIVersion ->
+ // APIVersion -> Log -> CapabilityValidator -> FeatureToggle -> StatsExporter ->
// SchedulerThriftInterface
+ // It's important for this interceptor to be registered first to ensure it's at the 'top' of
+ // the stack and the standard message is always applied.
+ bindThriftDecorator(new ServerInfoInterceptor());
+
// TODO(Sathya): Consider using provider pattern for constructing interceptors to facilitate
// unit testing without the creation of Guice injectors.
bindThriftDecorator(new LoggingInterceptor());
@@ -126,7 +130,6 @@ public class AopModule extends AbstractModule {
});
bindThriftDecorator(new FeatureToggleInterceptor());
bindThriftDecorator(new ThriftStatsExporterInterceptor());
- bindThriftDecorator(new ServerInfoInterceptor());
}
private void bindThriftDecorator(MethodInterceptor interceptor) {
http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/4e52d00b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
index 6089032..168290a 100644
--- a/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/thrift/SchedulerThriftInterfaceTest.java
@@ -16,6 +16,7 @@ package org.apache.aurora.scheduler.thrift;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -25,9 +26,11 @@ import java.util.UUID;
import javax.annotation.Nullable;
import com.google.common.base.Function;
+import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -74,9 +77,11 @@ import org.apache.aurora.gen.JobUpdateRequest;
import org.apache.aurora.gen.JobUpdateSettings;
import org.apache.aurora.gen.JobUpdateSummary;
import org.apache.aurora.gen.LimitConstraint;
+import org.apache.aurora.gen.ListBackupsResult;
import org.apache.aurora.gen.Lock;
import org.apache.aurora.gen.LockKey;
import org.apache.aurora.gen.PendingReason;
+import org.apache.aurora.gen.QueryRecoveryResult;
import org.apache.aurora.gen.Range;
import org.apache.aurora.gen.ResourceAggregate;
import org.apache.aurora.gen.Response;
@@ -147,6 +152,7 @@ import static org.apache.aurora.auth.CapabilityValidator.Capability.PROVISIONER;
import static org.apache.aurora.auth.CapabilityValidator.Capability.ROOT;
import static org.apache.aurora.auth.SessionValidator.SessionContext;
import static org.apache.aurora.gen.LockValidation.CHECKED;
+import static org.apache.aurora.gen.LockValidation.UNCHECKED;
import static org.apache.aurora.gen.MaintenanceMode.DRAINING;
import static org.apache.aurora.gen.MaintenanceMode.NONE;
import static org.apache.aurora.gen.MaintenanceMode.SCHEDULED;
@@ -161,6 +167,7 @@ import static org.apache.aurora.gen.apiConstants.THRIFT_API_VERSION;
import static org.apache.aurora.scheduler.configuration.ConfigurationManager.DEDICATED_ATTRIBUTE;
import static org.apache.aurora.scheduler.quota.QuotaCheckResult.Result.INSUFFICIENT_QUOTA;
import static org.apache.aurora.scheduler.quota.QuotaCheckResult.Result.SUFFICIENT_QUOTA;
+import static org.apache.aurora.scheduler.storage.backup.Recovery.RecoveryException;
import static org.apache.aurora.scheduler.thrift.SchedulerThriftInterface.MAX_TASKS_PER_JOB;
import static org.apache.aurora.scheduler.thrift.SchedulerThriftInterface.MAX_TASK_ID_LENGTH;
import static org.apache.aurora.scheduler.thrift.SchedulerThriftInterface.NOOP_JOB_UPDATE_MESSAGE;
@@ -575,9 +582,8 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
- public void testCreateHomogeneousJobNoShards() throws Exception {
+ public void testCreateHomogeneousJobNoInstances() throws Exception {
JobConfiguration job = makeJob();
- job.setInstanceCount(0);
job.unsetInstanceCount();
expectAuth(ROLE, true);
@@ -587,6 +593,17 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
+ public void testCreateJobNegativeInstanceCount() throws Exception {
+ JobConfiguration job = makeJob();
+ job.setInstanceCount(0 - 1);
+ expectAuth(ROLE, true);
+
+ control.replay();
+
+ assertResponse(INVALID_REQUEST, thrift.createJob(job, DEFAULT_LOCK, SESSION));
+ }
+
+ @Test
public void testCreateJobNoResources() throws Exception {
expectAuth(ROLE, true);
@@ -772,6 +789,19 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
+ public void testKillByJobName() throws Exception {
+ TaskQuery query = new TaskQuery().setJobName("job");
+ expectAuth(ROOT, true);
+ storageUtil.expectTaskFetch(Query.arbitrary(query).active(), buildScheduledTask());
+ lockManager.validateIfLocked(LOCK_KEY, Optional.<ILock>absent());
+ expectTransitionsToKilling();
+
+ control.replay();
+
+ assertEquals(okEmptyResponse(), thrift.killTasks(query, DEFAULT_LOCK, SESSION));
+ }
+
+ @Test
public void testKillQueryActive() throws Exception {
Query.Builder query = Query.unscoped().byJob(JOB_KEY);
expectAuth(ROOT, true);
@@ -1002,9 +1032,83 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
// Note: This will change after AOP-style session validation passes in a SessionContext.
expectAuth(ROOT, true).times(2);
+ // Auth for the second call. AOP auth fails, but second auth attempt required to get
+ // SessionContext fails. This is pretty contrived, but not technically impossible.
+ expectAuth(ROOT, true);
+ expectAuth(ROOT, false);
+
control.replay();
assertOkResponse(thrift.forceTaskState(TASK_ID, status, SESSION));
+ assertEquals(
+ response(AUTH_FAILED, Optional.<Result>absent(), AUTH_DENIED_MESSAGE),
+ thrift.forceTaskState(TASK_ID, status, SESSION));
+ }
+
+ @Test
+ public void testBackupControls() throws Exception {
+ expectAuth(ROOT, true);
+ backup.backupNow();
+
+ expectAuth(ROOT, true);
+ Set<String> backups = ImmutableSet.of("a", "b");
+ expect(recovery.listBackups()).andReturn(backups);
+
+ expectAuth(ROOT, true);
+ String backupId = "backup";
+ recovery.stage(backupId);
+
+ expectAuth(ROOT, true);
+ Query.Builder query = Query.taskScoped("taskId");
+ Set<IScheduledTask> queryResult = ImmutableSet.of(
+ IScheduledTask.build(new ScheduledTask().setStatus(ScheduleStatus.RUNNING)));
+ expect(recovery.query(query)).andReturn(queryResult);
+
+ expectAuth(ROOT, true);
+ recovery.deleteTasks(query);
+
+ expectAuth(ROOT, true);
+ recovery.commit();
+
+ expectAuth(ROOT, true);
+ recovery.unload();
+
+ control.replay();
+
+ assertEquals(okEmptyResponse(), thrift.performBackup(SESSION));
+
+ assertEquals(
+ okResponse(Result.listBackupsResult(new ListBackupsResult().setBackups(backups))),
+ thrift.listBackups(SESSION));
+
+ assertEquals(okEmptyResponse(), thrift.stageRecovery(backupId, SESSION));
+
+ assertEquals(
+ okResponse(Result.queryRecoveryResult(
+ new QueryRecoveryResult().setTasks(IScheduledTask.toBuildersSet(queryResult)))),
+ thrift.queryRecovery(query.get(), SESSION));
+
+ assertEquals(okEmptyResponse(), thrift.deleteRecoveryTasks(query.get(), SESSION));
+
+ assertEquals(okEmptyResponse(), thrift.commitRecovery(SESSION));
+
+ assertEquals(okEmptyResponse(), thrift.unloadRecovery(SESSION));
+ }
+
+ @Test
+ public void testRecoveryException() throws Exception {
+ Throwable recoveryException = new RecoveryException("Injected");
+
+ expectAuth(ROOT, true);
+ String backupId = "backup";
+ recovery.stage(backupId);
+ expectLastCall().andThrow(recoveryException);
+
+ control.replay();
+
+ assertEquals(
+ errorResponse(recoveryException.getMessage()),
+ thrift.stageRecovery(backupId, SESSION));
}
@Test
@@ -1287,6 +1391,49 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
+ public void testRewriteNoCommands() throws Exception {
+ expectAuth(ROOT, true);
+
+ control.replay();
+
+ RewriteConfigsRequest request = new RewriteConfigsRequest(ImmutableList.<ConfigRewrite>of());
+ assertResponse(INVALID_REQUEST, thrift.rewriteConfigs(request, SESSION));
+ }
+
+ @Test
+ public void testRewriteInvalidJob() throws Exception {
+ expectAuth(ROOT, true);
+
+ control.replay();
+
+ IJobConfiguration job = IJobConfiguration.build(makeJob());
+ RewriteConfigsRequest request = new RewriteConfigsRequest(
+ ImmutableList.of(ConfigRewrite.jobRewrite(
+ new JobConfigRewrite(job.newBuilder(), job.newBuilder().setTaskConfig(null)))));
+ assertResponse(ERROR, thrift.rewriteConfigs(request, SESSION));
+ }
+
+ @Test
+ public void testRewriteChangeJobKey() throws Exception {
+ expectAuth(ROOT, true);
+
+ control.replay();
+
+ IJobConfiguration job = IJobConfiguration.build(makeJob());
+ JobKey rewrittenJobKey = JobKeys.from("a", "b", "c").newBuilder();
+ Identity rewrittenIdentity = new Identity(rewrittenJobKey.getRole(), "steve");
+ RewriteConfigsRequest request = new RewriteConfigsRequest(
+ ImmutableList.of(ConfigRewrite.jobRewrite(new JobConfigRewrite(
+ job.newBuilder(),
+ job.newBuilder()
+ .setTaskConfig(job.getTaskConfig().newBuilder().setJob(rewrittenJobKey)
+ .setOwner(rewrittenIdentity))
+ .setOwner(rewrittenIdentity)
+ .setKey(rewrittenJobKey)))));
+ assertResponse(WARNING, thrift.rewriteConfigs(request, SESSION));
+ }
+
+ @Test
public void testRewriteShardCasMismatch() throws Exception {
TaskConfig storedConfig = productionTask();
TaskConfig modifiedConfig =
@@ -1313,7 +1460,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
- public void testRewriteShard() throws Exception {
+ public void testRewriteInstance() throws Exception {
TaskConfig storedConfig = productionTask();
ITaskConfig modifiedConfig = ITaskConfig.build(
storedConfig.deepCopy().setExecutorConfig(new ExecutorConfig("aurora", "rewritten")));
@@ -1346,6 +1493,37 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
+ public void testRewriteInstanceUnchanged() throws Exception {
+ TaskConfig config = productionTask();
+ String taskId = "task_id";
+ IScheduledTask task = IScheduledTask.build(new ScheduledTask().setAssignedTask(
+ new AssignedTask()
+ .setTaskId(taskId)
+ .setTask(config)));
+ InstanceKey instanceKey = new InstanceKey(
+ JobKeys.from(
+ config.getOwner().getRole(),
+ config.getEnvironment(),
+ config.getJobName()).newBuilder(),
+ 0);
+
+ expectAuth(ROOT, true);
+ storageUtil.expectTaskFetch(
+ Query.instanceScoped(IInstanceKey.build(instanceKey)).active(), task);
+ expect(storageUtil.taskStore.unsafeModifyInPlace(
+ taskId,
+ ITaskConfig.build(ConfigurationManager.applyDefaultsIfUnset(config.deepCopy()))))
+ .andReturn(false);
+
+ control.replay();
+
+ RewriteConfigsRequest request = new RewriteConfigsRequest(
+ ImmutableList.of(ConfigRewrite.instanceRewrite(
+ new InstanceConfigRewrite(instanceKey, config, config))));
+ assertResponse(WARNING, thrift.rewriteConfigs(request, SESSION));
+ }
+
+ @Test
public void testRewriteJobCasMismatch() throws Exception {
JobConfiguration oldJob = makeJob(productionTask());
JobConfiguration newJob = oldJob.deepCopy();
@@ -1353,8 +1531,8 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
String manager = "manager_key";
expectAuth(ROOT, true);
expect(storageUtil.jobStore.fetchManagerIds()).andReturn(ImmutableSet.of(manager));
- expect(storageUtil.jobStore.fetchJobs(manager))
- .andReturn(ImmutableList.of(IJobConfiguration.build(oldJob)));
+ expect(storageUtil.jobStore.fetchJob(manager, IJobKey.build(oldJob.getKey())))
+ .andReturn(Optional.of(IJobConfiguration.build(oldJob)));
control.replay();
@@ -1372,8 +1550,8 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
String manager = "manager_key";
expectAuth(ROOT, true);
expect(storageUtil.jobStore.fetchManagerIds()).andReturn(ImmutableSet.of(manager));
- expect(storageUtil.jobStore.fetchJobs(manager))
- .andReturn(ImmutableList.<IJobConfiguration>of());
+ expect(storageUtil.jobStore.fetchJob(manager, IJobKey.build(oldJob.getKey())))
+ .andReturn(Optional.<IJobConfiguration>absent());
control.replay();
@@ -1388,11 +1566,19 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
JobConfiguration oldJob = makeJob(productionTask());
JobConfiguration newJob = oldJob.deepCopy();
newJob.getTaskConfig().setExecutorConfig(new ExecutorConfig("aurora", "rewritten"));
- String manager = "manager_key";
+ String manager1 = "manager1";
+ String manager2 = "manager2";
+ String manager3 = "manager3";
expectAuth(ROOT, true);
- expect(storageUtil.jobStore.fetchManagerIds()).andReturn(ImmutableSet.of(manager));
- expect(storageUtil.jobStore.fetchJobs(manager))
- .andReturn(IJobConfiguration.listFromBuilders(ImmutableList.of(oldJob, makeJob())));
+ expect(storageUtil.jobStore.fetchManagerIds())
+ .andReturn(ImmutableSet.of(manager1, manager2, manager3));
+ expect(storageUtil.jobStore.fetchJob(manager1, IJobKey.build(oldJob.getKey())))
+ .andReturn(Optional.of(IJobConfiguration.build(oldJob)));
+ expect(storageUtil.jobStore.fetchJob(manager2, IJobKey.build(oldJob.getKey())))
+ .andReturn(Optional.of(IJobConfiguration.build(makeJob())));
+ expect(storageUtil.jobStore.fetchJob(manager3, IJobKey.build(oldJob.getKey())))
+ .andReturn(Optional.of(IJobConfiguration.build(
+ makeJob().setKey(JobKeys.from("1", "2", "3").newBuilder()))));
control.replay();
@@ -1410,8 +1596,8 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
String manager = "manager_key";
expectAuth(ROOT, true);
expect(storageUtil.jobStore.fetchManagerIds()).andReturn(ImmutableSet.of(manager));
- expect(storageUtil.jobStore.fetchJobs(manager))
- .andReturn(ImmutableList.of(IJobConfiguration.build(oldJob)));
+ expect(storageUtil.jobStore.fetchJob(manager, IJobKey.build(oldJob.getKey())))
+ .andReturn(Optional.of(IJobConfiguration.build(oldJob)));
storageUtil.jobStore.saveAcceptedJob(
manager,
ConfigurationManager.validateAndPopulate(IJobConfiguration.build(newJob)));
@@ -1579,12 +1765,42 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
return okResponse(Result.jobSummaryResult(new JobSummaryResult().setSummaries(jobSummaries)));
}
- private Response okResponse(Result result) {
- return Util.emptyResponse()
- .setResponseCode(OK)
+ private static final Function<String, ResponseDetail> MESSAGE_TO_DETAIL =
+ new Function<String, ResponseDetail>() {
+ @Override
+ public ResponseDetail apply(String message) {
+ return new ResponseDetail().setMessage(message);
+ }
+ };
+
+ private Response response(ResponseCode code, Optional<Result> result, String... messages) {
+ Response response = Util.emptyResponse()
+ .setResponseCode(code)
.setDEPRECATEDversion(API_VERSION)
.setServerInfo(SERVER_INFO)
- .setResult(result);
+ .setResult(result.orNull());
+ if (messages.length > 0) {
+ response.setMessageDEPRECATED(Joiner.on(", ").join(messages));
+ response
+ .setDetails(FluentIterable.from(Arrays.asList(messages)).transform(MESSAGE_TO_DETAIL)
+ .toList());
+ }
+
+ return response;
+ }
+
+ private Response okResponse(Result result) {
+ return response(OK, Optional.of(result));
+ }
+
+ private Response okEmptyResponse() {
+ return response(OK, Optional.<Result>absent());
+ }
+
+ private Response errorResponse(String message) {
+ return response(ERROR, Optional.<Result>absent())
+ .setMessageDEPRECATED(message)
+ .setDetails(ImmutableList.of(new ResponseDetail().setMessage(message)));
}
private Response invalidResponse(String message) {
@@ -2213,6 +2429,16 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
}
@Test
+ public void testReleaseLockUnchecked() throws Exception {
+ expectAuth(ROLE, true);
+ lockManager.releaseLock(LOCK);
+
+ control.replay();
+
+ assertEquals(okEmptyResponse(), thrift.releaseLock(LOCK.newBuilder(), UNCHECKED, SESSION));
+ }
+
+ @Test
public void testGetLocks() throws Exception {
expect(lockManager.getLocks()).andReturn(ImmutableSet.of(LOCK));
@@ -2530,7 +2756,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
control.replay();
JobUpdateRequest request = buildJobUpdateRequest(IJobUpdate.build(builder));
- assertResponse(OK, thrift.startJobUpdate(request, SESSION));
+ assertResponse(INVALID_REQUEST, thrift.startJobUpdate(request, SESSION));
}
@Test
@@ -2736,6 +2962,15 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
assertResponse(INVALID_REQUEST, thrift.abortJobUpdate(JOB_KEY.newBuilder(), SESSION));
}
+ @Test
+ public void testPulseJobUpdate() throws Exception {
+ control.replay();
+
+ assertEquals(
+ errorResponse(SchedulerThriftInterface.NOT_IMPLEMENTED_MESSAGE),
+ thrift.pulseJobUpdate("update", SESSION));
+ }
+
private static JobConfiguration makeProdJob() {
return makeJob(productionTask(), 1);
}
@@ -2770,12 +3005,14 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
.setKey(JOB_KEY.newBuilder());
}
+ private static final String AUTH_DENIED_MESSAGE = "Denied!";
+
private IExpectationSetters<?> expectAuth(Set<String> roles, boolean allowed)
throws AuthFailedException {
if (!allowed) {
return expect(userValidator.checkAuthenticated(SESSION, roles))
- .andThrow(new AuthFailedException("Denied!"));
+ .andThrow(new AuthFailedException(AUTH_DENIED_MESSAGE));
} else {
return expect(userValidator.checkAuthenticated(SESSION, roles))
.andReturn(context);
@@ -2795,7 +3032,7 @@ public class SchedulerThriftInterfaceTest extends EasyMockTest {
return expect(userValidator.checkAuthorized(
eq(SESSION),
eq(capability),
- anyObject(AuditCheck.class))).andThrow(new AuthFailedException("Denied!"));
+ anyObject(AuditCheck.class))).andThrow(new AuthFailedException(AUTH_DENIED_MESSAGE));
} else {
return expect(userValidator.checkAuthorized(
eq(SESSION),