| // Copyright 2023 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "persistent_service_test_lib.h" |
| |
| #include <inttypes.h> |
| |
| #include "ipc_utils.h" |
| #include "persistent_service.h" |
| #include "util.h" |
| |
| #define DEBUG 0 |
| |
| // Common macros used to print a prefix then an message to stderr. |
| #define STDERR_PRINTF(prefix, ...) \ |
| do { \ |
| fputs(prefix, stderr); \ |
| fprintf(stderr, __VA_ARGS__); \ |
| fputs("\n", stderr); \ |
| } while (0) |
| |
| #if DEBUG |
| #define SERVER_LOG(...) STDERR_PRINTF("TEST_SERVER: ", __VA_ARGS__) |
| #define CLIENT_LOG(...) STDERR_PRINTF("TEST_CLIENT: ", __VA_ARGS__) |
| #else |
| #define SERVER_LOG(...) (void)0 |
| #define CLIENT_LOG(...) (void)0 |
| #endif |
| |
| #define SERVER_ERR(...) STDERR_PRINTF("TEST_SERVER: ERROR: ", __VA_ARGS__) |
| #define SERVER_WARN(...) STDERR_PRINTF("TEST_SERVER: WARNING: ", __VA_ARGS__) |
| |
| #define CLIENT_ERR(...) STDERR_PRINTF("TEST_CLIENT: ERROR: ", __VA_ARGS__) |
| #define CLIENT_WARN(...) STDERR_PRINTF("TEST_CLIENT: WARNING: ", __VA_ARGS__) |
| |
| namespace { |
| |
| std::vector<std::string> GetServerArgs(const std::string* version) { |
| std::vector<std::string> result; |
| std::string program = |
| GetCurrentExecutableDir() + "/persistent_service_test_helper"; |
| #ifdef _WIN32 |
| program.append(".exe"); |
| #endif |
| result.push_back(std::move(program)); |
| if (version) |
| result.push_back(*version); |
| return result; |
| } |
| |
| // This is necessary because RemoteWrite("ping", ...) will send a 5-byte |
| // character sequence (including the terminating zero), instead of a |
| // string size + its content. |
| bool SendString(const char* str, IpcHandle& con, std::string* err) { |
| return RemoteWrite(std::string(str), con, err); |
| } |
| |
| } // namespace |
| |
| namespace persistent_service_test { |
| |
| const char kServiceName[] = "persistent-server-test"; |
| |
| const char kDefaultVersion[] = "default-version"; |
| |
| PersistentService::Config GetServerConfig() { |
| PersistentService::Config config(GetServerArgs(nullptr)); |
| return config.SetVersionInfo(kDefaultVersion); |
| } |
| |
| void SetServiceConfigVersion(PersistentService::Config& config, |
| const std::string& version) { |
| config.SetVersionInfo(version); |
| config.command.push_back(StringFormat("-v%s", version.c_str())); |
| } |
| |
| void SetServiceConfigTimeoutMs(PersistentService::Config& config, |
| int64_t connection_timeout_ms) { |
| config.command.push_back(StringFormat("-t%" PRId64, connection_timeout_ms)); |
| } |
| |
| PersistentService::Server::VersionCheckHandler GetVersionCheckHandler( |
| const std::string& server_version_info) { |
| return [server_version_info]( |
| const std::string& client_version_info) -> std::string { |
| if (client_version_info != server_version_info) { |
| return StringFormat("Version mismatch, expected [%s] got [%s]", |
| server_version_info.c_str(), |
| client_version_info.c_str()); |
| } |
| return {}; |
| }; |
| } |
| |
| bool RequestHandler(IpcHandle connection) { |
| std::string error; |
| std::string request; |
| bool is_first = true; |
| while (true) { |
| SERVER_LOG("Waiting for request"); |
| if (!RemoteRead(request, connection, &error)) { |
| if (!is_first) { |
| SERVER_LOG("Client connection closed"); |
| return true; |
| } |
| SERVER_ERR("Could not read request: %s\n", error.c_str()); |
| return false; |
| } |
| SERVER_LOG("Received request [%.*s]", (int)request.size(), request.c_str()); |
| |
| is_first = false; |
| |
| if (request == "kill-server") { |
| SERVER_LOG("TEST_SERVER: kill-server command received, exiting"); |
| return false; |
| } |
| |
| if (request == "ping") { |
| SERVER_LOG("TEST_SERVER: ping request received, sending reply"); |
| if (!SendString("pong", connection, &error)) { |
| SERVER_ERR("Could not send reply: %s\n", error.c_str()); |
| return false; |
| } |
| SERVER_LOG("pong sent"); |
| continue; |
| } |
| |
| SERVER_ERR("Unknown request [%s]\n", request.c_str()); |
| return false; |
| } |
| } |
| |
| bool RunTest(IpcHandle& client, bool kill_server, std::string* err) { |
| if (!SendString("ping", client, err)) { |
| CLIENT_ERR("Could not send test request: %s\n", err->c_str()); |
| return false; |
| } |
| std::string reply; |
| if (!RemoteRead(reply, client, err)) { |
| CLIENT_ERR("Could not receive test reply: %s\n", err->c_str()); |
| return false; |
| } |
| |
| bool success = (reply == "pong"); |
| if (!success) { |
| CLIENT_ERR("Invalid reply [%s] expected [pong]\n", reply.c_str()); |
| // Do not return here to ensure the server is killed. |
| } |
| |
| if (kill_server) { |
| if (!SendString("kill-server", client, err)) { |
| CLIENT_ERR("Could not kill server: %s\n", err->c_str()); |
| } |
| |
| PersistentService::Client persistent(kServiceName); |
| if (!persistent.WaitForServerShutdown()) { |
| CLIENT_WARN("Could not wait for server shutdown\n"); |
| } |
| } |
| return success; |
| } |
| |
| } // namespace persistent_service_test |