Docker provisioner local store unit tests. Review: https://reviews.apache.org/r/37495
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/85c1cd3a Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/85c1cd3a Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/85c1cd3a Branch: refs/heads/master Commit: 85c1cd3a51405ae7481f62b834ca76644c6f882a Parents: e8906a1 Author: Lily Chen <[email protected]> Authored: Thu Aug 13 11:23:36 2015 -0700 Committer: Timothy Chen <[email protected]> Committed: Fri Sep 25 09:02:04 2015 -0700 ---------------------------------------------------------------------- src/Makefile.am | 1 + .../containerizer/provisioner_docker_tests.cpp | 164 +++++++++++++++++++ 2 files changed, 165 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/85c1cd3a/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index 0b49a3b..40a6427 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1770,6 +1770,7 @@ mesos_tests_DEPENDENCIES = # Initialized to allow += below. if OS_LINUX mesos_tests_SOURCES += tests/containerizer/cgroups_isolator_tests.cpp mesos_tests_SOURCES += tests/containerizer/cgroups_tests.cpp + mesos_tests_SOURCES += tests/containerizer/docker_provisioner_tests.cpp mesos_tests_SOURCES += tests/containerizer/filesystem_isolator_tests.cpp mesos_tests_SOURCES += tests/containerizer/fs_tests.cpp mesos_tests_SOURCES += tests/containerizer/launch_tests.cpp http://git-wip-us.apache.org/repos/asf/mesos/blob/85c1cd3a/src/tests/containerizer/provisioner_docker_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/containerizer/provisioner_docker_tests.cpp b/src/tests/containerizer/provisioner_docker_tests.cpp index 1b0c304..3927009 100644 --- a/src/tests/containerizer/provisioner_docker_tests.cpp +++ b/src/tests/containerizer/provisioner_docker_tests.cpp @@ -21,6 +21,12 @@ #include <stout/duration.hpp> +#include <stout/gtest.hpp> +#include <stout/json.hpp> +#include <stout/os.hpp> +#include <stout/path.hpp> +#include <stout/stringify.hpp> + #include <process/address.hpp> #include <process/clock.hpp> #include <process/future.hpp> @@ -35,6 +41,7 @@ #include "slave/containerizer/provisioner/docker/token_manager.hpp" #include "tests/mesos.hpp" +#include "tests/utils.hpp" using std::map; using std::string; @@ -48,6 +55,10 @@ using process::Owned; using process::network::Socket; +using namespace process; +using namespace mesos::internal::slave; +using namespace mesos::internal::slave::docker; + using ManifestResponse = RegistryClient::ManifestResponse; namespace mesos { @@ -683,6 +694,159 @@ TEST_F(RegistryClientTest, BadRequest) #endif // USE_SSL_SOCKET +class DockerProvisionerLocalStoreTest : public TemporaryDirectoryTest +{ +public: + void verifyLocalDockerImage( + const slave::Flags& flags, + const DockerImage& dockerImage) + { + // Verify contents of the image in store directory. + EXPECT_TRUE( + os::exists(path::join(flags.docker_store_dir, "123", "rootfs"))); + EXPECT_TRUE( + os::exists(path::join(flags.docker_store_dir, "456", "rootfs"))); + EXPECT_SOME_EQ( + "foo 123", + os::read(path::join(flags.docker_store_dir, "123", "rootfs" , "temp"))); + EXPECT_SOME_EQ( + "bar 456", + os::read(path::join(flags.docker_store_dir, "456", "rootfs", "temp"))); + + // Verify the docker Image provided. + EXPECT_EQ(dockerImage.imageName, "abc"); + list<string> expectedLayers; + expectedLayers.push_back("123"); + expectedLayers.push_back("456"); + EXPECT_EQ(dockerImage.layers, expectedLayers); + } + +protected: + virtual void SetUp() + { + TemporaryDirectoryTest::SetUp(); + + string imageDir = path::join(os::getcwd(), "images"); + string image = path::join(imageDir, "abc"); + ASSERT_SOME(os::mkdir(imageDir)); + ASSERT_SOME(os::mkdir(image)); + + JSON::Value repositories = JSON::parse( + "{" + " \"abc\": {" + " \"latest\": \"456\"" + " }" + "}").get(); + ASSERT_SOME( + os::write(path::join(image, "repositories"), stringify(repositories))); + + ASSERT_SOME(os::mkdir(path::join(image, "123"))); + JSON::Value manifest123 = JSON::parse( + "{" + " \"parent\": \"\"" + "}").get(); + ASSERT_SOME(os::write( + path::join(image, "123", "json"), stringify(manifest123))); + ASSERT_SOME(os::mkdir(path::join(image, "123", "layer"))); + ASSERT_SOME( + os::write(path::join(image, "123", "layer", "temp"), "foo 123")); + + // Must change directory to avoid carrying over /path/to/archive during tar. + const string cwd = os::getcwd(); + ASSERT_SOME(os::chdir(path::join(image, "123", "layer"))); + ASSERT_SOME(os::tar(".", "../layer.tar")); + ASSERT_SOME(os::chdir(cwd)); + ASSERT_SOME(os::rmdir(path::join(image, "123", "layer"))); + + ASSERT_SOME(os::mkdir(path::join(image, "456"))); + JSON::Value manifest456 = JSON::parse( + "{" + " \"parent\": \"123\"" + "}").get(); + ASSERT_SOME( + os::write(path::join(image, "456", "json"), stringify(manifest456))); + ASSERT_SOME(os::mkdir(path::join(image, "456", "layer"))); + ASSERT_SOME( + os::write(path::join(image, "456", "layer", "temp"), "bar 456")); + + ASSERT_SOME(os::chdir(path::join(image, "456", "layer"))); + ASSERT_SOME(os::tar(".", "../layer.tar")); + ASSERT_SOME(os::chdir(cwd)); + ASSERT_SOME(os::rmdir(path::join(image, "456", "layer"))); + + ASSERT_SOME(os::chdir(image)); + ASSERT_SOME(os::tar(".", "../abc.tar")); + ASSERT_SOME(os::chdir(cwd)); + ASSERT_SOME(os::rmdir(image)); + } +}; + +// This test verifies that a locally stored Docker image in the form of a +// tar achive created from a 'docker save' command can be unpacked and +// stored in the proper locations accessible to the Docker provisioner. +TEST_F(DockerProvisionerLocalStoreTest, LocalStoreTestWithTar) +{ + string imageDir = path::join(os::getcwd(), "images"); + string image = path::join(imageDir, "abc"); + ASSERT_SOME(os::mkdir(imageDir)); + ASSERT_SOME(os::mkdir(image)); + + slave::Flags flags; + flags.docker_store = "local"; + flags.docker_store_dir = path::join(os::getcwd(), "store"); + flags.docker_discovery_local_dir = imageDir; + + // Fetcher is not relevant to local store. It is passed through from the + // provisioner interface. + Fetcher fetcher; + Try<Owned<Store>> store = Store::create(flags, &fetcher); + ASSERT_SOME(store); + + string sandbox = path::join(os::getcwd(), "sandbox"); + ASSERT_SOME(os::mkdir(sandbox)); + Future<DockerImage> dockerImage = store.get()->put("abc", sandbox); + AWAIT_READY(dockerImage); + + verifyLocalDockerImage(flags, dockerImage.get()); + + Future<Option<DockerImage>> dockerImageOption = store.get()->get("abc"); + AWAIT_READY(dockerImageOption); + ASSERT_SOME(dockerImageOption.get()); + verifyLocalDockerImage(flags, dockerImageOption.get().get()); +} + +// This tests the ability of the reference store to recover the images it has +// already stored on disk when it is initialized. +TEST_F(DockerProvisionerLocalStoreTest, ReferenceStoreInitialization) +{ + slave::Flags flags; + flags.docker_store = "local"; + flags.docker_store_dir = path::join(os::getcwd(), "store"); + flags.docker_discovery_local_dir = path::join(os::getcwd(), "images"); + + // Fetcher is not relevant to local store. It is passed through from the + // provisioner interface. + Fetcher fetcher; + Try<Owned<Store>> store = Store::create(flags, &fetcher); + ASSERT_SOME(store); + + string sandbox = path::join(os::getcwd(), "sandbox"); + ASSERT_SOME(os::mkdir(sandbox)); + Future<DockerImage> dockerImage = store.get()->put("abc", sandbox); + AWAIT_READY(dockerImage); + + // Store is deleted and recreated. Reference Store is initialized upon + // creation of the store. + store.get().reset(); + store = Store::create(flags, &fetcher); + ASSERT_SOME(store); + + Future<Option<DockerImage>> dockerImageOption = store.get()->get("abc"); + AWAIT_READY(dockerImageOption); + ASSERT_SOME(dockerImageOption.get()); + verifyLocalDockerImage(flags, dockerImageOption.get().get()); +} + } // namespace tests { } // namespace internal { } // namespace mesos {
