This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/http_admin_fix in repository https://gitbox.apache.org/repos/asf/celix.git
commit 3105275451813f34ab7e5dd867b9b41111e5f9a9 Author: Pepijn Noltes <[email protected]> AuthorDate: Sun Jun 20 21:59:37 2021 +0200 Refactors http_admin to use gtest and fixes a issue where a root request lead to a segfault. --- bundles/http_admin/CMakeLists.txt | 4 +- bundles/http_admin/gtest/CMakeLists.txt | 48 ++++ .../{test => gtest}/docroot/foo/bar/index.html | 0 .../test => gtest/src}/http_admin_info_tests.cc | 54 +++-- .../http_admin/gtest/src/http_websocket_tests.cc | 188 +++++++++++++++ .../{test/test => gtest/src}/sut_activator.c | 7 - bundles/http_admin/http_admin/src/http_admin.c | 6 +- bundles/http_admin/http_admin/src/service_tree.c | 8 +- bundles/http_admin/test/CMakeLists.txt | 69 ------ bundles/http_admin/test/config.properties.in | 25 -- .../http_admin/test/test/http_websocket_tests.cc | 251 --------------------- bundles/http_admin/test/test/test_runner.cc | 49 ---- 12 files changed, 271 insertions(+), 438 deletions(-) diff --git a/bundles/http_admin/CMakeLists.txt b/bundles/http_admin/CMakeLists.txt index a1dea64..a0c7b0d 100644 --- a/bundles/http_admin/CMakeLists.txt +++ b/bundles/http_admin/CMakeLists.txt @@ -23,7 +23,7 @@ if (HTTP_ADMIN) add_subdirectory(http_admin) if (ENABLE_TESTING) - add_subdirectory(test) - endif (ENABLE_TESTING) + add_subdirectory(gtest) + endif() endif (HTTP_ADMIN) diff --git a/bundles/http_admin/gtest/CMakeLists.txt b/bundles/http_admin/gtest/CMakeLists.txt new file mode 100644 index 0000000..93e2fb6 --- /dev/null +++ b/bundles/http_admin/gtest/CMakeLists.txt @@ -0,0 +1,48 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +find_package(Jansson REQUIRED) + +add_celix_bundle(http_admin_sut + #"Vanilla" bundle which is under test + SOURCES + src/sut_activator.c + VERSION 1.0.0 +) +target_include_directories(http_admin_sut PRIVATE test) +target_link_libraries(http_admin_sut PRIVATE Celix::http_admin_api) +celix_bundle_add_dir(http_admin_sut docroot DESTINATION ".") +celix_bundle_headers(http_admin_sut + "X-Web-Resource: /alias$<SEMICOLON>/docroot/foo/bar, /socket_alias$<SEMICOLON>/docroot/foo/bar" +) + +add_executable(http_websocket_tests + src/http_admin_info_tests.cc + src/http_websocket_tests.cc +) + +celix_get_bundle_file(Celix::http_admin HTTP_ADMIN_BUNDLE) +celix_get_bundle_file(http_admin_sut HTTP_ADMIN_SUT_BUNDLE) +target_compile_definitions(http_websocket_tests PRIVATE + HTTP_ADMIN_BUNDLE="${HTTP_ADMIN_BUNDLE}" + HTTP_ADMIN_SUT_BUNDLE="${HTTP_ADMIN_SUT_BUNDLE}" +) +target_link_libraries(http_websocket_tests PRIVATE Celix::framework Celix::http_admin_api GTest::gtest GTest::gtest_main) + +add_test(NAME http_websocket_tests COMMAND http_websocket_tests) +setup_target_for_coverage(http_websocket_tests SCAN_DIR ../http_admin) + diff --git a/bundles/http_admin/test/docroot/foo/bar/index.html b/bundles/http_admin/gtest/docroot/foo/bar/index.html similarity index 100% rename from bundles/http_admin/test/docroot/foo/bar/index.html rename to bundles/http_admin/gtest/docroot/foo/bar/index.html diff --git a/bundles/http_admin/test/test/http_admin_info_tests.cc b/bundles/http_admin/gtest/src/http_admin_info_tests.cc similarity index 57% rename from bundles/http_admin/test/test/http_admin_info_tests.cc rename to bundles/http_admin/gtest/src/http_admin_info_tests.cc index 8342005..848328a 100644 --- a/bundles/http_admin/test/test/http_admin_info_tests.cc +++ b/bundles/http_admin/gtest/src/http_admin_info_tests.cc @@ -17,38 +17,36 @@ * under the License. */ +#include <gtest/gtest.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "celix_api.h" +#include "celix/FrameworkFactory.h" #include "http_admin/api.h" -#include <CppUTest/TestHarness.h> -#include <CppUTestExt/MockSupport.h> -#include "celix_constants.h" +#define HTTP_PORT 45112 -extern celix_framework_t *fw; +class HttpInfoTestSuite : public ::testing::Test { +public: + HttpInfoTestSuite() { + celix::Properties config{ + {"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, + {"CELIX_HTTP_ADMIN_LISTENING_PORTS", std::to_string(HTTP_PORT) } + }; + fw = celix::createFramework(config); + ctx = fw->getFrameworkBundleContext(); -TEST_GROUP(HTTP_ADMIN_INFO_INT_GROUP) -{ - celix_bundle_context_t *ctx = nullptr; - void setup() { - if (fw != nullptr) { - ctx = celix_framework_getFrameworkContext(fw); - } - //Setup - } + long httpAdminBndId = ctx->installBundle(HTTP_ADMIN_BUNDLE); + EXPECT_GE(httpAdminBndId, 0); - void teardown() { - //Teardown - } -}; + long httpEndpointProviderBndId = ctx->installBundle(HTTP_ADMIN_SUT_BUNDLE); + EXPECT_GE(httpEndpointProviderBndId, 0); + } + std::shared_ptr<celix::Framework> fw{}; + std::shared_ptr<celix::BundleContext> ctx{}; +}; -TEST(HTTP_ADMIN_INFO_INT_GROUP, http_admin_info_test) { - CHECK(ctx != nullptr); +TEST_F(HttpInfoTestSuite, http_admin_info_test) { + EXPECT_TRUE(ctx != nullptr); celix_service_use_options_t opts{}; opts.filter.serviceName = HTTP_ADMIN_INFO_SERVICE_NAME; @@ -57,10 +55,10 @@ TEST(HTTP_ADMIN_INFO_INT_GROUP, http_admin_info_test) { opts.useWithProperties = [](void */*handle*/, void */*svc*/, const celix_properties_t *props) { long port = celix_properties_getAsLong(props, HTTP_ADMIN_INFO_PORT, -1L); const char *resources = celix_properties_get(props, HTTP_ADMIN_INFO_RESOURCE_URLS, ""); - CHECK_EQUAL(8000L, port); - STRCMP_EQUAL("/alias,/socket_alias", resources); + EXPECT_EQ(HTTP_PORT, port); + EXPECT_STREQ("/alias,/socket_alias", resources); }; - bool called = celix_bundleContext_useServiceWithOptions(ctx, &opts); - CHECK(called); + bool called = celix_bundleContext_useServiceWithOptions(ctx->getCBundleContext(), &opts); + EXPECT_TRUE(called); } diff --git a/bundles/http_admin/gtest/src/http_websocket_tests.cc b/bundles/http_admin/gtest/src/http_websocket_tests.cc new file mode 100644 index 0000000..c33cd9a --- /dev/null +++ b/bundles/http_admin/gtest/src/http_websocket_tests.cc @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <gtest/gtest.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "celix/FrameworkFactory.h" +#include "civetweb.h" + +#define HTTP_PORT 45111 + +class HttpAndWebsocketTestSuite : public ::testing::Test { +public: + HttpAndWebsocketTestSuite() { + celix::Properties config{ + {"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, + {"CELIX_HTTP_ADMIN_USE_WEBSOCKETS", "true"}, + {"CELIX_HTTP_ADMIN_LISTENING_PORTS", std::to_string(HTTP_PORT) } + }; + fw = celix::createFramework(config); + ctx = fw->getFrameworkBundleContext(); + + long httpAdminBndId = ctx->installBundle(HTTP_ADMIN_BUNDLE); + EXPECT_GE(httpAdminBndId, 0); + + long httpEndpointProviderBndId = ctx->installBundle(HTTP_ADMIN_SUT_BUNDLE); + EXPECT_GE(httpEndpointProviderBndId, 0); + } + + std::shared_ptr<celix::Framework> fw{}; + std::shared_ptr<celix::BundleContext> ctx{}; +}; + +//Local function prototypes +static int +websocket_client_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len, void *user_data); + +//Local type definitions +typedef struct socket_client_data { + char *data; + size_t length; +} socket_client_data_t; + +static void checkHttpRequest(const char* req_str, int expectedReturnCode) { + char err_buf[100] = {0}; + auto* connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); + + //Send request and check if complete request is send + auto send_bytes = mg_write(connection, req_str, strlen(req_str)); + EXPECT_TRUE(send_bytes == (int) strlen(req_str)); + + //Wait 1000ms for a response and check if response is successful + auto response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); + EXPECT_TRUE(response > 0); + + //If response is successful, check if the received response contains the info we expected + auto response_info = mg_get_response_info(connection); + EXPECT_TRUE(response_info != nullptr); + EXPECT_EQ(expectedReturnCode, response_info->status_code); + + mg_close_connection(connection); +} + +TEST_F(HttpAndWebsocketTestSuite, http_get_incex_test) { + checkHttpRequest("GET / HTTP/1.1\r\n\r\n", 200); +} + +TEST_F(HttpAndWebsocketTestSuite, http_get_test) { + checkHttpRequest("GET /alias/index.html HTTP/1.1\r\n\r\n", 200); +} + +TEST_F(HttpAndWebsocketTestSuite, http_get_file_not_existing_test) { + checkHttpRequest("GET /alias/test.html HTTP/1.1\r\n\r\n", 404); +} + +TEST_F(HttpAndWebsocketTestSuite, http_get_uri_not_existing_test) { + checkHttpRequest("GET /uri_not_existing/test.html HTTP/1.1\r\n\r\n", 404); +} + +TEST_F(HttpAndWebsocketTestSuite, http_request_not_existing_test) { + checkHttpRequest("CONNECT /test/test.html HTTP/1.1\r\n\r\n", 501); +} + +TEST_F(HttpAndWebsocketTestSuite, http_put_echo_alias_test) { + char err_buf[100] = {0}; + const char *data_str = "<html><body><p>Test PUT echo</p></body></html>"; + char rcv_buf[100] = {0}; + int send_bytes, response; + const struct mg_response_info *response_info; + struct mg_connection *connection; + + connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); + EXPECT_TRUE(connection != nullptr); + + //Send request and check if complete request is send + send_bytes = mg_printf(connection, "PUT /alias/index.html HTTP/1.1\r\n" + "Content-Type: text/html\r\n" + "Content-Length: %d\r\n\r\n", (int) strlen(data_str)); + //send_bytes = mg_write(connection, req_str, strlen(req_str)); + send_bytes += mg_write(connection, data_str, strlen(data_str)); + EXPECT_TRUE(send_bytes > 0); + + //Wait 1000ms for a response and check if response is successful + response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); + EXPECT_TRUE(response > 0); + + //If response is successful, check if the received response contains the info we expected + response_info = mg_get_response_info(connection); + EXPECT_TRUE(response_info != nullptr); + int read_bytes = mg_read(connection, rcv_buf, sizeof(rcv_buf)); + + EXPECT_EQ(200, response_info->status_code); + + //Expect an echo which is the same as the request body + //NOTE seems that we sometimes get some extra trailing spaces. + EXPECT_TRUE(read_bytes >= (int)strlen(data_str)); + EXPECT_EQ(0, strncmp(data_str, rcv_buf, strlen(data_str))); + + mg_close_connection(connection); +} + +TEST_F(HttpAndWebsocketTestSuite, websocket_echo_test) { + char err_buf[100] = {0}; + const char *data_str = "Example data string used for testing"; + socket_client_data_t echo_data; + int bytes_written; + struct mg_connection *connection; + + //Prepare buffer for receiving echo data + echo_data.length = strlen(data_str); + echo_data.data = (char *) malloc(strlen(data_str)); + + connection = mg_connect_websocket_client("127.0.0.1", HTTP_PORT, 0, err_buf, sizeof(err_buf), + "/", "websocket_test", websocket_client_data_handler, nullptr, &echo_data); + EXPECT_TRUE(connection != nullptr); + + + bytes_written = mg_websocket_client_write(connection, MG_WEBSOCKET_OPCODE_TEXT, data_str, strlen(data_str)); + EXPECT_TRUE(bytes_written > 0); + + usleep(1000000); //Sleep for one second to let Civetweb handle the request + + //Check if data received is the same as the data sent! + EXPECT_TRUE(strncmp(echo_data.data, data_str, bytes_written) == 0); + + //Free/close used resources + free(echo_data.data); + mg_close_connection(connection); +} + +static int +websocket_client_data_handler(struct mg_connection *conn __attribute__((unused)), + int flags __attribute__((unused)), + char *data, + size_t data_len, + void *user_data){ + + if(user_data != nullptr){ + auto *client_data = (socket_client_data_t *) user_data; + //Only copy when data length is equal or less then expected client data length + if(data_len <= client_data->length) { + memcpy(client_data->data, data, data_len); + } + } + + return 0; //return 0 means close connection + +} \ No newline at end of file diff --git a/bundles/http_admin/test/test/sut_activator.c b/bundles/http_admin/gtest/src/sut_activator.c similarity index 95% rename from bundles/http_admin/test/test/sut_activator.c rename to bundles/http_admin/gtest/src/sut_activator.c index d8510a8..aefe461 100644 --- a/bundles/http_admin/test/test/sut_activator.c +++ b/bundles/http_admin/gtest/src/sut_activator.c @@ -16,13 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -/** - * sut_activator.c - * - * \date Jun 7, 2019 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ #include <stdlib.h> diff --git a/bundles/http_admin/http_admin/src/http_admin.c b/bundles/http_admin/http_admin/src/http_admin.c index 20b2287..cfc2c94 100755 --- a/bundles/http_admin/http_admin/src/http_admin.c +++ b/bundles/http_admin/http_admin/src/http_admin.c @@ -186,12 +186,12 @@ void http_admin_removeHttpService(void *handle, void *svc __attribute__((unused) int http_request_handle(struct mg_connection *connection) { int ret_status = 400; //Default bad request - if(connection != NULL) { + if (connection != NULL) { const struct mg_request_info *ri = mg_get_request_info(connection); http_admin_manager_t *admin = (http_admin_manager_t *) ri->user_data; service_tree_node_t *node = NULL; - if(mg_get_header(connection, "Upgrade") != NULL) { + if (mg_get_header(connection, "Upgrade") != NULL) { //Assume this is a websocket request... ret_status = 0; //... so return zero to let the civetweb server handle the request. } @@ -199,7 +199,7 @@ int http_request_handle(struct mg_connection *connection) { const char *req_uri = ri->request_uri; node = findServiceNodeInTree(&admin->http_svc_tree, req_uri); - if(node != NULL) { + if (node != NULL) { //Requested URI with node exists, now obtain the http service and call the requested function. celix_http_service_t *httpSvc = (celix_http_service_t *) node->svc_data->service; diff --git a/bundles/http_admin/http_admin/src/service_tree.c b/bundles/http_admin/http_admin/src/service_tree.c index 1066708..da0ae30 100644 --- a/bundles/http_admin/http_admin/src/service_tree.c +++ b/bundles/http_admin/http_admin/src/service_tree.c @@ -291,13 +291,13 @@ service_tree_node_t *findServiceNodeInTree(service_tree_t *svc_tree, const char char *uri_cpy; bool tree_not_empty = false; - if(svc_tree != NULL && uri != NULL) { + if (svc_tree != NULL && uri != NULL) { tree_not_empty = ((bool) (svc_tree->tree_svc_count | svc_tree->tree_node_count) & (svc_tree->root_node != NULL)); current = svc_tree->root_node; } - if(tree_not_empty){ + if (tree_not_empty) { if(strcmp(current->svc_data->sub_uri, "root") == 0) { asprintf(&uri_cpy, "%s%s", "root", uri); @@ -307,8 +307,8 @@ service_tree_node_t *findServiceNodeInTree(service_tree_t *svc_tree, const char char *uri_token = strtok_r(uri_cpy, "/", &save_ptr); //Check for horizontal matches for the first token - while(current != NULL) { - if(strcmp(current->svc_data->sub_uri, uri_token) == 0){ + while (current != NULL) { + if (uri_token != NULL && strcmp(current->svc_data->sub_uri, uri_token) == 0){ //Save current node to comply with OSGI Http Whiteboard Specification if(current->svc_data->service != NULL) { found_node = current; diff --git a/bundles/http_admin/test/CMakeLists.txt b/bundles/http_admin/test/CMakeLists.txt deleted file mode 100644 index 8f6de88..0000000 --- a/bundles/http_admin/test/CMakeLists.txt +++ /dev/null @@ -1,69 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. - -find_package(CppUTest REQUIRED) -find_package(Jansson REQUIRED) - -add_celix_bundle(http_admin_sut - #"Vanilla" bundle which is under test - SOURCES - test/sut_activator.c - VERSION 1.0.0 -) -target_include_directories(http_admin_sut PRIVATE test) -target_link_libraries(http_admin_sut PRIVATE Celix::http_admin_api) -celix_bundle_add_dir(http_admin_sut docroot DESTINATION ".") -celix_bundle_headers(http_admin_sut - "X-Web-Resource: /alias$<SEMICOLON>/docroot/foo/bar, /socket_alias$<SEMICOLON>/docroot/foo/bar" -) - -#add_celix_bundle(http_admin_tst -# #Test bundle containing cpputests and uses celix_test_runner launcher instead of the celix launcher -# SOURCES -# test/http_websocket_tests.cc -# VERSION 1.0.0 -#) -#target_link_libraries(http_admin_tst PRIVATE Celix::framework Celix::http_admin_api) -#target_include_directories(http_admin_tst SYSTEM PRIVATE ${CppUTest_INCLUDE_DIR}) -#celix_bundle_private_libs(http_admin_tst civetweb_shared) - - -add_celix_container(http_websocket_tests - LAUNCHER_SRC ${CMAKE_CURRENT_LIST_DIR}/test/test_runner.cc - DIR ${CMAKE_CURRENT_BINARY_DIR} - PROPERTIES - LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG=true - BUNDLES - Celix::http_admin - http_admin_sut -# http_admin_tst -) -target_sources(http_websocket_tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/test/http_websocket_tests.cc ${CMAKE_CURRENT_SOURCE_DIR}/test/http_admin_info_tests.cc) -target_link_libraries(http_websocket_tests PRIVATE Celix::http_admin_api ${CppUTest_LIBRARIES}) -target_include_directories(http_websocket_tests SYSTEM PRIVATE ${CppUTest_INCLUDE_DIR}) - -add_test(NAME http_websocket_tests COMMAND http_websocket_tests WORKING_DIRECTORY $<TARGET_PROPERTY:http_websocket_tests,CONTAINER_LOC>) -setup_target_for_coverage(http_websocket_tests SCAN_DIR ${CMAKE_BINARY_DIR}/bundles/http_admin/http_admin) - -get_target_property(http_admin_service_cmp Celix::http_admin BUNDLE_FILE) -get_target_property(http_admin_sut_cmp http_admin_sut BUNDLE_FILE) -#get_target_property(http_admin_tst_cmp http_admin_tst BUNDLE_FILE) -set(loghelper_std_out_fallback_incl_debug true) -set(use_websockets true) -set(listening_ports 65536) #Set invalid port to test range functionality -configure_file(${CMAKE_CURRENT_LIST_DIR}/config.properties.in ${CMAKE_CURRENT_BINARY_DIR}/http_websocket_tests/config.properties) - diff --git a/bundles/http_admin/test/config.properties.in b/bundles/http_admin/test/config.properties.in deleted file mode 100644 index 67f8ed4..0000000 --- a/bundles/http_admin/test/config.properties.in +++ /dev/null @@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. - -CELIX_CONTAINER_NAME=http_websocket_tests -CELIX_BUNDLES_PATH=bundles - -CELIX_AUTO_START_3=@http_admin_service_cmp@ @http_admin_sut_cmp@ - -CELIX_HTTP_ADMIN_USE_WEBSOCKETS=@use_websockets@ -CELIX_HTTP_ADMIN_LISTENING_PORTS=@listening_ports@ -LOGHELPER_STD_OUT_FALLBACK_INCLUDE_DEBUG=@loghelper_std_out_fallback_incl_debug@ \ No newline at end of file diff --git a/bundles/http_admin/test/test/http_websocket_tests.cc b/bundles/http_admin/test/test/http_websocket_tests.cc deleted file mode 100644 index 1db9f74..0000000 --- a/bundles/http_admin/test/test/http_websocket_tests.cc +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -/** - * http_websocket_tests.c - * - * \date Jun 7, 2019 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> - -#include "celix_api.h" -#include "http_admin/api.h" - -#include "civetweb.h" - -#include <CppUTest/TestHarness.h> -#include <CppUTestExt/MockSupport.h> -#include "celix_constants.h" - -#define HTTP_PORT 8000 - -//Local function prototypes -static int -websocket_client_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len, void *user_data); - -//Local type definitions -typedef struct socket_client_data { - char *data; - size_t length; -} socket_client_data_t; - - -TEST_GROUP(HTTP_ADMIN_INT_GROUP) -{ - void setup() { - //Setup - } - - void teardown() { - //Teardown - } -}; - - -TEST(HTTP_ADMIN_INT_GROUP, http_get_test) { - char err_buf[100] = {0}; - const char *req_str = "GET /alias/index.html HTTP/1.1\r\n\r\n"; - int send_bytes, response; - const struct mg_response_info *response_info; - struct mg_connection *connection; - - connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); - CHECK(connection != nullptr); - - //Send request and check if complete request is send - send_bytes = mg_write(connection, req_str, strlen(req_str)); - CHECK(send_bytes == (int) strlen(req_str)); - - //Wait 1000ms for a response and check if response is successful - response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); - CHECK(response > 0); - - //If response is successful, check if the received response contains the info we expected - response_info = mg_get_response_info(connection); - CHECK(response_info != nullptr); - CHECK(response_info->status_code == 200); - - mg_close_connection(connection); -} - -TEST(HTTP_ADMIN_INT_GROUP, http_get_file_not_existing_test) { - char err_buf[100] = {0}; - const char *get_req_str = "GET /alias/test.html HTTP/1.1\r\n\r\n"; - int send_bytes, response; - const struct mg_response_info *response_info; - struct mg_connection *connection; - - connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); - CHECK(connection != nullptr); - - send_bytes = mg_write(connection, get_req_str, strlen(get_req_str)); - CHECK(send_bytes == (int) strlen(get_req_str)); - - //Wait 1000ms for a response and check if response is successful - response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); - CHECK(response > 0); - - //If response is successful, check if the received response contains the info we expected - response_info = mg_get_response_info(connection); - CHECK(response_info != nullptr); - CHECK(response_info->status_code == 404); //File should not exist! - - mg_close_connection(connection); -} - -TEST(HTTP_ADMIN_INT_GROUP, http_get_uri_not_existing_test) { - char err_buf[100] = {0}; - const char *get_req_str = "GET /uri_not_existing/test.html HTTP/1.1\r\n\r\n"; - int send_bytes, response; - const struct mg_response_info *response_info; - struct mg_connection *connection; - - connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); - CHECK(connection != nullptr); - - send_bytes = mg_write(connection, get_req_str, strlen(get_req_str)); - CHECK(send_bytes == (int) strlen(get_req_str)); - - //Wait 1000ms for a response and check if response is successful - response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); - CHECK(response > 0); - - //If response is successful, check if the received response contains the info we expected - response_info = mg_get_response_info(connection); - CHECK(response_info != nullptr); - CHECK(response_info->status_code == 404); //File should not exist! - - mg_close_connection(connection); -} - -TEST(HTTP_ADMIN_INT_GROUP, http_request_not_existing_test) { - char err_buf[100] = {0}; - const char *get_req_str = "CONNECT /test/test.html HTTP/1.1\r\n\r\n"; //CONNECT is not implemented - int send_bytes, response; - const struct mg_response_info *response_info; - struct mg_connection *connection; - - connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); - CHECK(connection != nullptr); - - send_bytes = mg_write(connection, get_req_str, strlen(get_req_str)); - CHECK(send_bytes == (int) strlen(get_req_str)); - - //Wait 1000ms for a response and check if response is successful - response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); - CHECK(response > 0); - - //If response is successful, check if the received response contains the info we expected - response_info = mg_get_response_info(connection); - CHECK(response_info != nullptr); - CHECK(response_info->status_code == 501); //Not implemented - - mg_close_connection(connection); -} - -TEST(HTTP_ADMIN_INT_GROUP, http_put_echo_alias_test) { - char err_buf[100] = {0}; - const char *data_str = "<html><body><p>Test PUT echo</p></body></html>"; - char rcv_buf[100] = {0}; - int send_bytes, response; - const struct mg_response_info *response_info; - struct mg_connection *connection; - - connection = mg_connect_client("localhost", HTTP_PORT /*port*/, 0 /*no ssl*/, err_buf, sizeof(err_buf)); - CHECK(connection != nullptr); - - //Send request and check if complete request is send - send_bytes = mg_printf(connection, "PUT /alias/index.html HTTP/1.1\r\n" - "Content-Type: text/html\r\n" - "Content-Length: %d\r\n\r\n", (int) strlen(data_str)); - //send_bytes = mg_write(connection, req_str, strlen(req_str)); - send_bytes += mg_write(connection, data_str, strlen(data_str)); - CHECK(send_bytes > 0); - - //Wait 1000ms for a response and check if response is successful - response = mg_get_response(connection, err_buf, sizeof(err_buf), 1000); - CHECK(response > 0); - - //If response is successful, check if the received response contains the info we expected - response_info = mg_get_response_info(connection); - CHECK(response_info != nullptr); - int read_bytes = mg_read(connection, rcv_buf, sizeof(rcv_buf)); - - CHECK_EQUAL(200, response_info->status_code); - - //Expect an echo which is the same as the request body - //NOTE seems that we sometimes get some extra trailing spaces. - CHECK(read_bytes >= (int)strlen(data_str)); - STRNCMP_EQUAL(data_str, rcv_buf, strlen(data_str)); - - mg_close_connection(connection); -} - -TEST(HTTP_ADMIN_INT_GROUP, websocket_echo_test) { - char err_buf[100] = {0}; - const char *data_str = "Example data string used for testing"; - socket_client_data_t echo_data; - int bytes_written; - struct mg_connection *connection; - - //Prepare buffer for receiving echo data - echo_data.length = strlen(data_str); - echo_data.data = (char *) malloc(strlen(data_str)); - - connection = mg_connect_websocket_client("127.0.0.1", HTTP_PORT, 0, err_buf, sizeof(err_buf), - "/", "websocket_test", websocket_client_data_handler, nullptr, &echo_data); - CHECK(connection != nullptr); - - - bytes_written = mg_websocket_client_write(connection, MG_WEBSOCKET_OPCODE_TEXT, data_str, strlen(data_str)); - CHECK(bytes_written > 0); - - usleep(1000000); //Sleep for one second to let Civetweb handle the request - - //Check if data received is the same as the data sent! - CHECK(strncmp(echo_data.data, data_str, bytes_written) == 0); - - //Free/close used resources - free(echo_data.data); - mg_close_connection(connection); -} - -static int -websocket_client_data_handler(struct mg_connection *conn __attribute__((unused)), - int flags __attribute__((unused)), - char *data, - size_t data_len, - void *user_data){ - - if(user_data != nullptr){ - auto *client_data = (socket_client_data_t *) user_data; - //Only copy when data length is equal or less then expected client data length - if(data_len <= client_data->length) { - memcpy(client_data->data, data, data_len); - } - } - - return 0; //return 0 means close connection - -} \ No newline at end of file diff --git a/bundles/http_admin/test/test/test_runner.cc b/bundles/http_admin/test/test/test_runner.cc deleted file mode 100644 index 5a285f1..0000000 --- a/bundles/http_admin/test/test/test_runner.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -/** - * test_runner.c - * - * \date Jun 7, 2019 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ - -#include <unistd.h> - -#include "celix_api.h" - -#include <CppUTest/TestHarness.h> -#include <CppUTest/CommandLineTestRunner.h> - -celix_framework_t *fw = nullptr; - - -int main(int argc, char **argv) { - celixLauncher_launch("config.properties", &fw); - //usleep(1000000); - - MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); - int rc = RUN_ALL_TESTS(argc, argv); - - celixLauncher_stop(fw); - celixLauncher_waitForShutdown(fw); - celixLauncher_destroy(fw); - - return rc; -} \ No newline at end of file
