/* * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. * Description: ps llt * Author: wujing * Create: 2019-12-19 */ #include "ps.h" #include #include #include #include #include #include "grpc_client_mock.h" #include "utils.h" using ::testing::Args; using ::testing::ByRef; using ::testing::SetArgPointee; using ::testing::DoAll; using ::testing::NiceMock; using ::testing::Return; using ::testing::NotNull; using ::testing::AtLeast; using ::testing::Invoke; using ::testing::_; using namespace std; class ContainerListUnitTest : public testing::Test { public: void SetUp() override { GrpcClient_SetMock(&m_grpcClient); ::testing::Mock::AllowLeak(&m_grpcClient); } void TearDown() override { GrpcClient_SetMock(nullptr); } NiceMock m_grpcClient; }; namespace { unsigned generate_random_pid() { constexpr int pid_start = 10000; constexpr int pid_end = 10000; static default_random_engine e(time(0)); static uniform_int_distribution u(pid_start, pid_end); return u(e); } long long generate_random_created() { // unix nanos: 2019-01-01T00:00:00.000000000+08:00 constexpr int64_t start = 1546272000000000000ll; // unix nanos: 2019-12-31T00:00:00.000000000+08:00 constexpr int64_t end = 1577721600000000000ll; static default_random_engine e(time(0)); static uniform_int_distribution u(start, end); return u(e); } string generate_random_string(int length) { static string chset = "abcdefghijklmnopqrstuvwxyz1234567890"; string result; result.resize(length); srand(time(NULL)); for (int i = 0; i < length; i++) { static default_random_engine e(time(0)); static uniform_int_distribution u(0, chset.size() - 1); result[i] = chset[u(e) % chset.length()]; } return result; } int set_container_summary(struct isula_list_response *response, int index) { constexpr int id_len = 64; constexpr int name_len = 8; response->container_summary[index] = (struct isula_container_summary_info *)util_common_calloc_s( sizeof(struct isula_container_summary_info)); if (response->container_summary[index] == nullptr) { return -1; } response->container_summary[index]->id = util_strdup_s(generate_random_string(id_len).c_str()); response->container_summary[index]->name = util_strdup_s(generate_random_string(name_len).c_str()); response->container_summary[index]->runtime = util_strdup_s("lcr"); response->container_summary[index]->pid = generate_random_pid(); response->container_summary[index]->status = (Container_Status)CONTAINER_STATUS_RUNNING; response->container_summary[index]->image = util_strdup_s("busybox:latest"); response->container_summary[index]->command = util_strdup_s("/bin/sh"); response->container_summary[index]->startat = util_strdup_s("2019-12-31T23:55:50.867369507+08:00"); response->container_summary[index]->finishat = util_strdup_s("2020-01-01T23:55:50.867369507+08:00"); response->container_summary[index]->exit_code = 0; response->container_summary[index]->restart_count = 0; response->container_summary[index]->created = generate_random_created(); response->container_summary[index]->health_state = util_strdup_s("(healthy)"); response->container_num++; return 0; } } // namespace int ContainerList(const struct isula_list_request *request, struct isula_list_response *response, void *arg) { (void)request; (void)arg; constexpr int container_cnt = 5; response->cc = 0; response->server_errono = 0; response->errmsg = nullptr; response->container_summary = (struct isula_container_summary_info **)util_common_calloc_s( sizeof(struct isula_container_summary_info *) * container_cnt); if (response->container_summary == nullptr) { return -1; } for (size_t i {}; i < container_cnt; ++i) { if (set_container_summary(response, i)) { return -1; } } return 0; } int invokeGrpcOpsInit(isula_connect_ops *ops) { if (ops == nullptr) { return -1; } ops->container.list = &ContainerList; return 0; } TEST_F(ContainerListUnitTest, test_cmd_list_main_all) { const char *argv[] = {"isula", "ps", "-a"}; const char *argv_failure[] = {"isula", "ps", "-k"}; isula_connect_ops ops; ops.container.list = &ContainerList; EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)) .WillOnce(Return(-1)) .WillOnce(DoAll(SetArgPointee<0>(ByRef(ops)), Return(0))); ASSERT_EQ(connect_client_ops_init(), -1); ASSERT_EQ(connect_client_ops_init(), 0); EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), testing::ExitedWithCode(0), ""); EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); ASSERT_EQ(connect_client_ops_init(), 0); EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), testing::ExitedWithCode(0), ""); EXPECT_EXIT(cmd_list_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), testing::ExitedWithCode(125), "Unkown flag found"); testing::Mock::VerifyAndClearExpectations(&m_grpcClient); } TEST_F(ContainerListUnitTest, test_cmd_list_main_format) { const char *argv[] = { "isula", "ps", "-a", "--format", "\"table XXX{{.ID}}AAA{{.Image}}" " {{.Status}} {{.Pid}} {{.Command}} {{.Created}} {{.Ports}} {{.ExitCode}} " "{{.RestartCount}} {{.StartAt}} {{.FinishAt}} {{.Runtime}} \t{{.Names}} \n{{.State}}\"" }; const char *argv_failure[] = {"isula", "ps", "--format", "\"{{.ID}} {{.XXX}}"}; EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); ASSERT_EQ(connect_client_ops_init(), 0); EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), testing::ExitedWithCode(0), ""); EXPECT_EXIT(cmd_list_main(sizeof(argv_failure) / sizeof(argv_failure[0]), const_cast(argv_failure)), testing::ExitedWithCode(1), "not support the field"); testing::Mock::VerifyAndClearExpectations(&m_grpcClient); } TEST_F(ContainerListUnitTest, test_cmd_list_main_notrunc) { const char *argv[] = {"isula", "ps", "-q", "--no-trunc"}; testing::internal::CaptureStdout(); EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); ASSERT_EQ(connect_client_ops_init(), 0); EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), testing::ExitedWithCode(0), ""); std::string output = testing::internal::GetCapturedStdout(); if (output.find("CONTAINER ID") != std::string::npos) { ADD_FAILURE() << "the output of command('isula ps -q --no-trunc') should not include table headers"; } std::cout << "Gtest Captured Stdout:" << std::endl << output; testing::Mock::VerifyAndClearExpectations(&m_grpcClient); } TEST_F(ContainerListUnitTest, test_cmd_list_main_debug) { const char *argv[] = {"isula", "ps", "-a", "-D"}; testing::internal::CaptureStdout(); EXPECT_CALL(m_grpcClient, GrpcOpsInit(_)).WillRepeatedly(Invoke(invokeGrpcOpsInit)); ASSERT_EQ(connect_client_ops_init(), 0); EXPECT_EXIT(cmd_list_main(sizeof(argv) / sizeof(argv[0]), const_cast(argv)), testing::ExitedWithCode(0), ""); std::string output = testing::internal::GetCapturedStdout(); std::vector tableItems {"CONTAINER ID", "IMAGE", "COMMAND", "CREATED", "STATUS", "PORTS", "NAMES"}; for (const auto &elem : tableItems) { if (output.find(elem) == std::string::npos) { ADD_FAILURE() << "container list info should include " << elem; } } if (output.find("healthy") == std::string::npos) { FAIL() << "container list info should include healthy"; } std::cout << "Gtest Captured Stdout:" << std::endl << output; testing::Mock::VerifyAndClearExpectations(&m_grpcClient); SUCCEED() << "test isula ps --debug success"; }