From d596829c7ec3e6279983434cee1bc9a5c8a33016 Mon Sep 17 00:00:00 2001 From: Guilherme Amadio Date: Tue, 14 Mar 2023 15:07:03 +0100 Subject: [PATCH] [Tests] Convert tests of XrdCl::URL from CppUnit to Google Test --- tests/CMakeLists.txt | 2 + tests/XrdCl/CMakeLists.txt | 18 ++++ tests/XrdCl/XrdClURL.cc | 131 ++++++++++++++++++++++ tests/XrdClTests/UtilsTest.cc | 197 ---------------------------------- 4 files changed, 151 insertions(+), 197 deletions(-) create mode 100644 tests/XrdCl/CMakeLists.txt create mode 100644 tests/XrdCl/XrdClURL.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b1c0171075c..4a9b7923676 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,5 @@ +include(GoogleTest) +add_subdirectory( XrdCl ) add_subdirectory( common ) add_subdirectory( XrdClTests ) diff --git a/tests/XrdCl/CMakeLists.txt b/tests/XrdCl/CMakeLists.txt new file mode 100644 index 00000000000..a114c4cb620 --- /dev/null +++ b/tests/XrdCl/CMakeLists.txt @@ -0,0 +1,18 @@ + +add_executable(xrdcl-unit-tests + XrdClURL.cc +) + +target_link_libraries(xrdcl-unit-tests + XrdCl + XrdXml + XrdUtils + GTest::GTest + GTest::Main +) + +target_include_directories(xrdcl-unit-tests + PRIVATE ${CMAKE_SOURCE_DIR}/src +) + +gtest_discover_tests(xrdcl-unit-tests TEST_PREFIX XrdCl::) diff --git a/tests/XrdCl/XrdClURL.cc b/tests/XrdCl/XrdClURL.cc new file mode 100644 index 00000000000..24e7fdc2aad --- /dev/null +++ b/tests/XrdCl/XrdClURL.cc @@ -0,0 +1,131 @@ +#undef NDEBUG + +#include +#include + +#include +#include + +using namespace testing; + +// Test that XrdCl::URL conforms to RFC1738 (https://www.rfc-editor.org/rfc/rfc1738) + +class URLTest : public ::testing::Test {}; + +TEST(URLTest, LocalURLs) +{ + char url[PATH_MAX]; + for (const auto& protocol : { "", "file://" }) { + for (const auto& path : { "/dev", "/dev/", "/dev/null" }) { + for (const auto& params : { "", "?param=value", "?param1=value1¶m2=value2" }) { + snprintf(url, sizeof(url), "%s%s%s", protocol, path, params); + + XrdCl::URL local_url(url); + + EXPECT_TRUE(local_url.IsValid()) << "URL " << url << " is invalid" << std::endl; + + EXPECT_EQ(local_url.GetProtocol(), "file"); + + EXPECT_EQ(local_url.GetHostId(), "localhost"); + EXPECT_EQ(local_url.GetHostName(), "localhost"); + + const char *resolved_path = realpath(path, nullptr); + snprintf(url, sizeof(url), "%s%s", resolved_path, params); + + EXPECT_STREQ(local_url.GetPath().c_str(), resolved_path); + EXPECT_STREQ(local_url.GetPathWithParams().c_str(), url); + EXPECT_STREQ(local_url.GetParamsAsString().c_str(), params); + + free((void*)resolved_path); + } + } + } +} + +TEST(URLTest, RemoteURLs) +{ + char url[PATH_MAX]; + char path_params[PATH_MAX]; + for (const char *protocol : { "", "http", "root", "https", "roots" }) { + int default_port = *protocol == 'h' ? (strlen(protocol) == 4 ? 80 : 443) : 1094; + for (const char *user : { "", "alice", "bob", "user_123", "xrootd" }) { + for (const char *password : { "", "abc ABC 123", "symbols \\~`!#$%^&*()_-+={[}]|:;'\"<,>.?" }) { + for (const char *host : { "localhost", "[::1]", "127.0.0.1", "eospilot.cern.ch" }) { + for (const char *port : { "", "-1", "1094", "9999", "65535" }) { + for (const char *path : { "", "/", "/data", "/data/", "/data/file.dat", "/data//file" }) { + for (const char *params : { "", "?param=value", "?param1=value1¶m2=value2" }) { + snprintf(url, sizeof(url), "%s%s%s%s%s%s%s%s%s%s%s%s", + protocol, *protocol ? "://" : "", + // TODO: allow empty user and/or password in the login part + user, *user && *password ? ":" : "", *user ? password : "", *user ? "@" : "", + // TODO: accept URLs with empty path and non-empty parameters + host, *port ? ":" : "", port, *params && !*path ? "/" : "", path, params); + snprintf(path_params, sizeof(path_params), "%s%s", *path == '/' ? path+1 : path, params); + + XrdCl::URL remote_url(url); + + EXPECT_TRUE(remote_url.IsValid()) << "URL " << url << " is invalid" << std::endl; + EXPECT_EQ(remote_url.GetPort(), *port ? atoi(port) : default_port); + EXPECT_STREQ(remote_url.GetProtocol().c_str(), *protocol ? protocol : "root"); + EXPECT_STREQ(remote_url.GetPassword().c_str(), *user && *password ? password : ""); + EXPECT_STREQ(remote_url.GetHostName().c_str(), host); + EXPECT_STREQ(remote_url.GetPath().c_str(), *path == '/' ? path+1 : path); + EXPECT_STREQ(remote_url.GetParamsAsString().c_str(), params); + EXPECT_STREQ(remote_url.GetPathWithParams().c_str(), path_params); + } + } + } + } + } + } + } + + XrdCl::URL complex_url( + /* protocol, login, host, and port */ + "root://xrootd:fxG}+u;B@lxfsra02a08.cern.ch:9999/" + /* path */ + "/eos/dev/SMWZd3pdExample_NTUP_SMWZ.526666._000073.root.1?" + /* parameters */ + "&cap.sym=sfdDqALWo3W3tWUJ2O5XwQ5GG8U=" + "&cap.msg=eGj/mh+9TrecFBAZBNr/nLau4p0kjlEOjc1JC+9DVjL1Tq+g" + "eBCIz/kKs261mnL4dJeUu6r25acCn4vhyp8UKyL1cVmmnyBnjqe6tz28q" + "FO2#0fQHrHf6Z9N0MNhw1fplYjpGeNwFH2jQSfSo24zSZKGa/PKClGYnX" + "&mgm.loginid=766877e6-9874-11e1-a77f-003048cf8cd8" + "&mgm.replicaindex=0" + "&mgm.replicahead=1" + ); + + EXPECT_TRUE(complex_url.IsValid()); + EXPECT_EQ(complex_url.GetPort(), 9999); + EXPECT_STREQ(complex_url.GetProtocol().c_str(), "root"); + EXPECT_STREQ(complex_url.GetUserName().c_str(), "xrootd"); + EXPECT_STREQ(complex_url.GetPassword().c_str(), "fxG}+u;B"); + EXPECT_STREQ(complex_url.GetHostName().c_str(), "lxfsra02a08.cern.ch"); + EXPECT_STREQ(complex_url.GetPath().c_str(), "/eos/dev/SMWZd3pdExample_NTUP_SMWZ.526666._000073.root.1"); + EXPECT_EQ(complex_url.GetParams().size(), 5); + + auto params = complex_url.GetParams(); + + EXPECT_EQ(params["cap.sym"], "sfdDqALWo3W3tWUJ2O5XwQ5GG8U="); + EXPECT_EQ(params["mgm.loginid"], "766877e6-9874-11e1-a77f-003048cf8cd8"); + EXPECT_EQ(params["mgm.replicaindex"], "0"); + EXPECT_EQ(params["mgm.replicahead"], "1"); +} + +TEST(URLTest, InvalidURLs) +{ + const char *invalid_urls[] = { + "root://", + "://asds", + "root:////path?param1=val1¶m2=val2", + "root://@//path?param1=val1¶m2=val2", + "root://:@//path?param1=val1¶m2=val2", + "root://asd@://path?param1=val1¶m2=val2" + "root://user1:passwd1host1:123//path?param1=val1¶m2=val2", + "root://user1:passwd1@host1:asd//path?param1=val1¶m2=val2", + }; + + for (const auto& url : invalid_urls) + EXPECT_FALSE(XrdCl::URL(url).IsValid()) << "URL " << url << " is not invalid" << std::endl; +} + diff --git a/tests/XrdClTests/UtilsTest.cc b/tests/XrdClTests/UtilsTest.cc index 368ca63ddd9..86104bc57f7 100644 --- a/tests/XrdClTests/UtilsTest.cc +++ b/tests/XrdClTests/UtilsTest.cc @@ -24,7 +24,6 @@ #include #include "CppUnitXrdHelpers.hh" -#include "XrdCl/XrdClURL.hh" #include "XrdCl/XrdClAnyObject.hh" #include "XrdCl/XrdClTaskManager.hh" #include "XrdCl/XrdClSIDManager.hh" @@ -37,13 +36,11 @@ class UtilsTest: public CppUnit::TestCase { public: CPPUNIT_TEST_SUITE( UtilsTest ); - CPPUNIT_TEST( URLTest ); CPPUNIT_TEST( AnyTest ); CPPUNIT_TEST( TaskManagerTest ); CPPUNIT_TEST( SIDManagerTest ); CPPUNIT_TEST( PropertyListTest ); CPPUNIT_TEST_SUITE_END(); - void URLTest(); void AnyTest(); void TaskManagerTest(); void SIDManagerTest(); @@ -52,200 +49,6 @@ class UtilsTest: public CppUnit::TestCase CPPUNIT_TEST_SUITE_REGISTRATION( UtilsTest ); -//------------------------------------------------------------------------------ -// URL test -//------------------------------------------------------------------------------ -void UtilsTest::URLTest() -{ - XrdCl::URL url1( "root://user1:passwd1@host1:123//path?param1=val1¶m2=val2" ); - XrdCl::URL url2( "root://user1@host1//path?param1=val1¶m2=val2" ); - XrdCl::URL url3( "root://host1" ); - XrdCl::URL url4( "root://user1:passwd1@[::1]:123//path?param1=val1¶m2=val2" ); - XrdCl::URL url5( "root://user1@192.168.1.1:123//path?param1=val1¶m2=val2" ); - XrdCl::URL url6( "root://[::1]" ); - XrdCl::URL url7( "root://lxfsra02a08.cern.ch:1095//eos/dev/SMWZd3pdExample_NTUP_SMWZ.526666._000073.root.1?&cap.sym=sfdDqALWo3W3tWUJ2O5XwQ5GG8U=&cap.msg=eGj/mh+9TrecFBAZBNr/nLau4p0kjlEOjc1JC+9DVjLL1Tq+g311485W0baMBAsM#W8lNFdVQcKNAu8K5yVskIcLDOEi6oNpvoxDA1DN4oCxtHR6LkOWhO91MLn/ZosJ5#Dc7aeBCIz/kKs261mnL4dJeUu6r25acCn4vhyp8UKyL1cVmmnyBnjqe6tz28qFO2#0fQHrHf6Z9N0MNhw1fplYjpGeNwFH2jQSfSo24zSZKGa/PKClGYnXoXBWDGU1spm#kJsGGrErhBHYvLq3eS+jEBr8l+c1BhCQU7ZaLZiyaKOnspYnR/Tw7bMrooWMh7eL#&mgm.logid=766877e6-9874-11e1-a77f-003048cf8cd8&mgm.recdcdcdcdplicaindex=0&mgm.replicahead=0" ); - XrdCl::URL url8( "/etc/passwd" ); - XrdCl::URL url9( "localhost:1094//data/cb4aacf1-6f28-42f2-b68a-90a73460f424.dat" ); - XrdCl::URL url10( "localhost:1094/?test=123" ); - - XrdCl::URL urlInvalid1( "root://user1:passwd1@host1:asd//path?param1=val1¶m2=val2" ); - XrdCl::URL urlInvalid2( "root://user1:passwd1host1:123//path?param1=val1¶m2=val2" ); - XrdCl::URL urlInvalid3( "root:////path?param1=val1¶m2=val2" ); - XrdCl::URL urlInvalid4( "root://@//path?param1=val1¶m2=val2" ); - XrdCl::URL urlInvalid5( "root://:@//path?param1=val1¶m2=val2" ); - XrdCl::URL urlInvalid6( "root://" ); - XrdCl::URL urlInvalid7( "://asds" ); - XrdCl::URL urlInvalid8( "root://asd@://path?param1=val1¶m2=val2" ); - - //---------------------------------------------------------------------------- - // Full url - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url1.IsValid() == true ); - CPPUNIT_ASSERT( url1.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url1.GetUserName() == "user1" ); - CPPUNIT_ASSERT( url1.GetPassword() == "passwd1" ); - CPPUNIT_ASSERT( url1.GetHostName() == "host1" ); - CPPUNIT_ASSERT( url1.GetPort() == 123 ); - CPPUNIT_ASSERT( url1.GetPathWithParams() == "/path?param1=val1¶m2=val2" ); - CPPUNIT_ASSERT( url1.GetPath() == "/path" ); - CPPUNIT_ASSERT( url1.GetParams().size() == 2 ); - - XrdCl::URL::ParamsMap::const_iterator it; - it = url1.GetParams().find( "param1" ); - CPPUNIT_ASSERT( it != url1.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val1" ); - it = url1.GetParams().find( "param2" ); - CPPUNIT_ASSERT( it != url1.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val2" ); - it = url1.GetParams().find( "param3" ); - CPPUNIT_ASSERT( it == url1.GetParams().end() ); - - //---------------------------------------------------------------------------- - // No password, no port - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url2.IsValid() == true ); - CPPUNIT_ASSERT( url2.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url2.GetUserName() == "user1" ); - CPPUNIT_ASSERT( url2.GetPassword() == "" ); - CPPUNIT_ASSERT( url2.GetHostName() == "host1" ); - CPPUNIT_ASSERT( url2.GetPort() == 1094 ); - CPPUNIT_ASSERT( url2.GetPath() == "/path" ); - CPPUNIT_ASSERT( url2.GetPathWithParams() == "/path?param1=val1¶m2=val2" ); - CPPUNIT_ASSERT( url1.GetParams().size() == 2 ); - - it = url2.GetParams().find( "param1" ); - CPPUNIT_ASSERT( it != url2.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val1" ); - it = url2.GetParams().find( "param2" ); - CPPUNIT_ASSERT( it != url2.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val2" ); - it = url2.GetParams().find( "param3" ); - CPPUNIT_ASSERT( it == url2.GetParams().end() ); - - //---------------------------------------------------------------------------- - // Just the host and the protocol - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url3.IsValid() == true ); - CPPUNIT_ASSERT( url3.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url3.GetUserName() == "" ); - CPPUNIT_ASSERT( url3.GetPassword() == "" ); - CPPUNIT_ASSERT( url3.GetHostName() == "host1" ); - CPPUNIT_ASSERT( url3.GetPort() == 1094 ); - CPPUNIT_ASSERT( url3.GetPath() == "" ); - CPPUNIT_ASSERT( url3.GetPathWithParams() == "" ); - CPPUNIT_ASSERT( url3.GetParams().size() == 0 ); - - //---------------------------------------------------------------------------- - // Full url - IPv6 - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url4.IsValid() == true ); - CPPUNIT_ASSERT( url4.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url4.GetUserName() == "user1" ); - CPPUNIT_ASSERT( url4.GetPassword() == "passwd1" ); - CPPUNIT_ASSERT( url4.GetHostName() == "[::1]" ); - CPPUNIT_ASSERT( url4.GetPort() == 123 ); - CPPUNIT_ASSERT( url4.GetPathWithParams() == "/path?param1=val1¶m2=val2" ); - CPPUNIT_ASSERT( url4.GetPath() == "/path" ); - CPPUNIT_ASSERT( url4.GetParams().size() == 2 ); - - it = url4.GetParams().find( "param1" ); - CPPUNIT_ASSERT( it != url4.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val1" ); - it = url4.GetParams().find( "param2" ); - CPPUNIT_ASSERT( it != url4.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val2" ); - it = url4.GetParams().find( "param3" ); - CPPUNIT_ASSERT( it == url4.GetParams().end() ); - - //---------------------------------------------------------------------------- - // No password, no port - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url5.IsValid() == true ); - CPPUNIT_ASSERT( url5.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url5.GetUserName() == "user1" ); - CPPUNIT_ASSERT( url5.GetPassword() == "" ); - CPPUNIT_ASSERT( url5.GetHostName() == "192.168.1.1" ); - CPPUNIT_ASSERT( url5.GetPort() == 123 ); - CPPUNIT_ASSERT( url5.GetPath() == "/path" ); - CPPUNIT_ASSERT( url5.GetPathWithParams() == "/path?param1=val1¶m2=val2" ); - CPPUNIT_ASSERT( url5.GetParams().size() == 2 ); - - it = url5.GetParams().find( "param1" ); - CPPUNIT_ASSERT( it != url5.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val1" ); - it = url5.GetParams().find( "param2" ); - CPPUNIT_ASSERT( it != url2.GetParams().end() ); - CPPUNIT_ASSERT( it->second == "val2" ); - it = url5.GetParams().find( "param3" ); - CPPUNIT_ASSERT( it == url5.GetParams().end() ); - - //---------------------------------------------------------------------------- - // Just the host and the protocol - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url6.IsValid() == true ); - CPPUNIT_ASSERT( url6.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url6.GetUserName() == "" ); - CPPUNIT_ASSERT( url6.GetPassword() == "" ); - CPPUNIT_ASSERT( url6.GetHostName() == "[::1]" ); - CPPUNIT_ASSERT( url6.GetPort() == 1094 ); - CPPUNIT_ASSERT( url6.GetPath() == "" ); - CPPUNIT_ASSERT( url6.GetPathWithParams() == "" ); - CPPUNIT_ASSERT( url6.GetParams().size() == 0 ); - - //---------------------------------------------------------------------------- - // Local file - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url8.IsValid() == true ); - CPPUNIT_ASSERT( url8.GetProtocol() == "file" ); - CPPUNIT_ASSERT( url8.GetUserName() == "" ); - CPPUNIT_ASSERT( url8.GetPassword() == "" ); - CPPUNIT_ASSERT( url8.GetHostName() == "localhost" ); - CPPUNIT_ASSERT( url8.GetPath() == "/etc/passwd" ); - CPPUNIT_ASSERT( url8.GetHostId() == "localhost" ); - CPPUNIT_ASSERT( url8.GetPathWithParams() == "/etc/passwd" ); - CPPUNIT_ASSERT( url8.GetParams().size() == 0 ); - - //---------------------------------------------------------------------------- - // URL without a protocol spec - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url9.IsValid() == true ); - CPPUNIT_ASSERT( url9.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url9.GetUserName() == "" ); - CPPUNIT_ASSERT( url9.GetPassword() == "" ); - CPPUNIT_ASSERT( url9.GetHostName() == "localhost" ); - CPPUNIT_ASSERT( url9.GetPort() == 1094 ); - CPPUNIT_ASSERT( url9.GetPath() == "/data/cb4aacf1-6f28-42f2-b68a-90a73460f424.dat" ); - - CPPUNIT_ASSERT( url9.GetPathWithParams() == "/data/cb4aacf1-6f28-42f2-b68a-90a73460f424.dat" ); - CPPUNIT_ASSERT( url9.GetParams().size() == 0 ); - - //---------------------------------------------------------------------------- - // URL cgi without path - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( url10.IsValid() == true ); - CPPUNIT_ASSERT( url10.GetProtocol() == "root" ); - CPPUNIT_ASSERT( url10.GetUserName() == "" ); - CPPUNIT_ASSERT( url10.GetPassword() == "" ); - CPPUNIT_ASSERT( url10.GetHostName() == "localhost" ); - CPPUNIT_ASSERT( url10.GetPort() == 1094 ); - CPPUNIT_ASSERT( url10.GetPath() == "" ); - - CPPUNIT_ASSERT( url10.GetParams().size() == 1 ); - CPPUNIT_ASSERT( url10.GetParamsAsString() == "?test=123" ); - - //---------------------------------------------------------------------------- - // Bunch od invalid ones - //---------------------------------------------------------------------------- - CPPUNIT_ASSERT( urlInvalid1.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid2.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid3.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid4.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid5.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid6.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid7.IsValid() == false ); - CPPUNIT_ASSERT( urlInvalid8.IsValid() == false ); -} - class A { public: