This is an automated email from the ASF dual-hosted git repository.

qianzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit b7c3da5a28fb46b4517d52872aec504fff098967
Author: Qian Zhang <zhq527...@gmail.com>
AuthorDate: Sun May 17 23:30:38 2020 +0800

    Added a test `ROOT_CommandTaskNoRootfsWithUnmountVolumeFailure`.
    
    Review: https://reviews.apache.org/r/72523
---
 .../containerizer/docker_volume_isolator_tests.cpp | 188 +++++++++++++++++++++
 1 file changed, 188 insertions(+)

diff --git a/src/tests/containerizer/docker_volume_isolator_tests.cpp 
b/src/tests/containerizer/docker_volume_isolator_tests.cpp
index 88d0dc7..ef58f7d 100644
--- a/src/tests/containerizer/docker_volume_isolator_tests.cpp
+++ b/src/tests/containerizer/docker_volume_isolator_tests.cpp
@@ -43,6 +43,8 @@
 
 namespace slave = mesos::internal::slave;
 
+using process::Clock;
+using process::Failure;
 using process::Future;
 using process::Owned;
 
@@ -1675,6 +1677,192 @@ TEST_F(DockerVolumeIsolatorTest,
   driver.join();
 }
 
+
+// This test verifies that unmount operation can be still invoked for
+// a docker volume even the previous unmount operation for the same
+// docker volume failed. This is a regression test for MESOS-10126.
+TEST_F(DockerVolumeIsolatorTest, 
ROOT_CommandTaskNoRootfsWithUnmountVolumeFailure)
+{
+  Clock::pause();
+
+  master::Flags masterFlags = CreateMasterFlags();
+
+  Try<Owned<cluster::Master>> master = StartMaster(masterFlags);
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.docker_volume_checkpoint_dir = path::join(os::getcwd(), "checkpoint");
+
+  MockDockerVolumeDriverClient* mockClient = new MockDockerVolumeDriverClient;
+
+  Try<Owned<MesosContainerizer>> containerizer =
+    createContainerizer(flags, Owned<DriverClient>(mockClient));
+
+  ASSERT_SOME(containerizer);
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer->get(),
+      flags);
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers1;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers1));
+
+  driver.start();
+
+  Clock::advance(masterFlags.allocation_interval);
+
+  AWAIT_READY(offers1);
+  ASSERT_FALSE(offers1->empty());
+
+  const Offer& offer1 = offers1.get()[0];
+
+  // Create a docker volume with relative path.
+  const string volumeDriver = "driver";
+  const string volumeName = "name";
+  const string containerPath = "tmp/foo";
+
+  Volume volume = createDockerVolume(volumeDriver, volumeName, containerPath);
+
+  // Launch the first task with the docker volume.
+  TaskInfo task1 = createTask(
+      offer1.slave_id(),
+      offer1.resources(),
+      "test -f " + containerPath + "/file");
+
+  ContainerInfo containerInfo;
+  containerInfo.set_type(ContainerInfo::MESOS);
+  containerInfo.add_volumes()->CopyFrom(volume);
+
+  task1.mutable_container()->CopyFrom(containerInfo);
+
+  // Create mount point for the volume.
+  const string mountPoint = path::join(os::getcwd(), "volume");
+  ASSERT_SOME(os::mkdir(mountPoint));
+  ASSERT_SOME(os::touch(path::join(mountPoint, "file")));
+
+  Future<string> mountName1;
+  EXPECT_CALL(*mockClient, mount(volumeDriver, _, _))
+    .WillOnce(DoAll(FutureArg<1>(&mountName1),
+                    Return(mountPoint)));
+
+  // Simulate an unmount failure.
+  Future<string> unmountName1;
+  EXPECT_CALL(*mockClient, unmount(volumeDriver, _))
+    .WillOnce(DoAll(FutureArg<1>(&unmountName1),
+                    Return(Failure("Mock failure"))));
+
+  Future<TaskStatus> statusStarting1;
+  Future<TaskStatus> statusRunning1;
+  Future<TaskStatus> statusFinished1;
+
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusStarting1))
+    .WillOnce(FutureArg<1>(&statusRunning1))
+    .WillOnce(FutureArg<1>(&statusFinished1));
+
+  Future<vector<Offer>> offers2;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers2))
+    .WillRepeatedly(Return());
+
+  driver.launchTasks(offer1.id(), {task1});
+
+  AWAIT_READY(statusStarting1);
+  EXPECT_EQ(TASK_STARTING, statusStarting1->state());
+
+  AWAIT_READY(statusRunning1);
+  EXPECT_EQ(TASK_RUNNING, statusRunning1->state());
+
+  // Make sure the docker volume mount parameters are same with the
+  // parameters in `containerInfo`.
+  AWAIT_EXPECT_EQ(volumeName, mountName1);
+
+  AWAIT_READY(statusFinished1);
+  EXPECT_EQ(TASK_FINISHED, statusFinished1->state());
+
+  Clock::resume();
+
+  // Make sure the docker volume unmount parameters are same with
+  // the parameters in `containerInfo`.
+  AWAIT_EXPECT_EQ(volumeName, unmountName1);
+
+  Clock::pause();
+  Clock::settle();
+  Clock::advance(masterFlags.allocation_interval);
+
+  AWAIT_READY(offers2);
+  ASSERT_FALSE(offers2->empty());
+
+  const Offer& offer2 = offers2.get()[0];
+
+  // Launch the second task with the same docker volume.
+  TaskInfo task2 = createTask(
+      offer2.slave_id(),
+      offer2.resources(),
+      "test -f " + containerPath + "/file");
+
+  task2.mutable_container()->CopyFrom(containerInfo);
+
+  Future<string> mountName2;
+  EXPECT_CALL(*mockClient, mount(volumeDriver, _, _))
+    .WillOnce(DoAll(FutureArg<1>(&mountName2),
+                    Return(mountPoint)));
+
+  Future<string> unmountName2;
+  EXPECT_CALL(*mockClient, unmount(volumeDriver, _))
+    .WillOnce(DoAll(FutureArg<1>(&unmountName2),
+                    Return(Nothing())));
+
+  Future<TaskStatus> statusStarting2;
+  Future<TaskStatus> statusRunning2;
+  Future<TaskStatus> statusFinished2;
+
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusStarting2))
+    .WillOnce(FutureArg<1>(&statusRunning2))
+    .WillOnce(FutureArg<1>(&statusFinished2));
+
+  driver.launchTasks(offer2.id(), {task2});
+
+  AWAIT_READY(statusStarting2);
+  EXPECT_EQ(TASK_STARTING, statusStarting2->state());
+
+  AWAIT_READY(statusRunning2);
+  EXPECT_EQ(TASK_RUNNING, statusRunning2->state());
+
+  // Make sure the docker volume mount parameters are same with the
+  // parameters in `containerInfo`.
+  AWAIT_EXPECT_EQ(volumeName, mountName2);
+
+  AWAIT_READY(statusFinished2);
+  EXPECT_EQ(TASK_FINISHED, statusFinished2->state());
+
+  Clock::resume();
+
+  // Check the unmount operation can still be invoked even the
+  // previous one failed.
+  AWAIT_EXPECT_EQ(volumeName, unmountName2);
+
+  driver.stop();
+  driver.join();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

Reply via email to