[+]文章目录

Mesos测试模式

在 Mesos 测试中,常使用的测试模式是集合。如果你有好的觉得有用的测试方法,请写下来并加上相关的动机和背景。

使用Clock确保事件的执行

调度异步环境中的事件顺序并非易事: 函数调用通常启动操作然后立即返回,而其中的操作在后台运行。一种简单、 明显和并不好的解决方案是使用 os::sleep() 来等待操作完成。在不同的机器上完成的时间不同,而增加了测试执行时间也就增加了睡眠时间以及最终减慢了检查时间。一种好的方法是,做到之一是等待操作一完成就执行。这可能要用到 libprocess 的Clock 检测。

每个消息队列在一个libprocess 进程的 (或执行者,目的是为了避免歧义的操作系统进程) mailbox 是由 ProcessManager (每个 OS 进程ProcessManager 所拥有的当前一个单例 ,但这可能会在以后改变) 处理的。 ProcessManager从可执行者列表中取来执行者列表,然后服务于执行者mailbox中的所有事件。通过调用Clock::settle(),我们可以阻止调用线程,直到 ProcessManager 执行完所有执行者mailbox中的事件。例子如下:

// As Master::killTask isn't doing anything, we shouldn't get a status update.
EXPECT_CALL(sched, statusUpdate(&driver, _))
  .Times(0);

// Set expectation that Master receives killTask message.
Future<KillTaskMessage> killTaskMessage =
  FUTURE_PROTOBUF(KillTaskMessage(), _, master.get());

// Attempt to kill unknown task while slave is transitioning.
TaskID unknownTaskId;
unknownTaskId.set_value("2");

// Stop the clock.
Clock::pause();

// Initiate an action.
driver.killTask(unknownTaskId);

// Make sure the event associated with the action has been queued.
AWAIT_READY(killTaskMessage);

// Wait for all messages to be dispatched and processed completely to satisfy
// the expectation that we didn't receive a status update.
Clock::settle();

Clock::resume();

拦截一条发送到不同的操作系统进程的消息

截获发送于libprocess 进程(我们称之为actors(执行者),为了避免与操作系统进程产生歧义)间的消息,这些执行者在同一个操作系统的进程,这个方法是容易的,例子如下:

Future<SlaveReregisteredMessage> slaveReregisteredMessage =
  FUTURE_PROTOBUF(SlaveReregisteredMessage(), _, _);
...
AWAIT_READY(slaveReregisteredMessage);

但是,如果我们想要拦截发送到另一个操作系统进程中actor (技术上 是 UPID) 的消息,这个方法就不管用了。例如,在我们的测试中(见 mesos/src/tests/cluster.hpp),虽然主设备和从设备实例在同一操作系统的进程上,但是slave上的 CommandExecutor 却是在一个独立的操作系统进程中,这样的话wait在代码中将会失效:

Future<ExecutorRegisteredMessage> executorRegisteredMessage =
  FUTURE_PROTOBUF(ExecutorRegisteredMessage(), _, _);
...
AWAIT_READY(executorRegisteredMessage);

为什么OS进程外部发送的信息不会被拦截?

Libprocess事件也许会被过滤(见libprocess/include/process/filter.hpp )。FUTURE_PROTOBUF 使用了这个功能,它设置了一个过滤期望值,是通过TestsFilter类的filter 方法与MessageMatcher 实现的,MessageMatcher 会匹配我们想要拦截的消息。过滤真正起作用的是ProcessManager::resume(),它从所接收的事件的队列中提取消息。

发送,编码,或传送信息时不发生过滤(见ProcessManager::deliver() 或 SocketManager::send()) 。因此,在上述例子中, 通过过滤器,ExecutorRegisteredMessage会留下未被探测的slave,直达另一个操作系统进程中的执行者,被入队到theCommandExecutorProcess的mailbox,然后在这里过滤,但不要忘了,我们的过滤期望配置是在前一个操作系统的进程中!

考虑在相应的传入消息设置过滤期望值,确保它们被处理,然后再返回确认信息(译者注:ACK消息)。

对于上述的例子,代替截取ExecutorRegisteredMessage,我们可以拦截RegisterExecutorMessage并等到其被处理了,包括发送ExecutorRegisteredMessage (见Slave::registerExecutor()) :

Future<RegisterExecutorMessage> registerExecutorMessage =
  FUTURE_PROTOBUF(RegisterExecutorMessage(), _, _);
...
AWAIT_READY(registerExecutorMessage);
Clock::pause();
Clock::settle();
Clock::resume();

« 前一篇