Skip to content

Commit

Permalink
[Tests] Convert tests of XrdCl::URL from CppUnit to Google Test
Browse files Browse the repository at this point in the history
  • Loading branch information
amadio committed Mar 15, 2023
1 parent a2ac4af commit d596829
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 197 deletions.
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
@@ -1,3 +1,5 @@
include(GoogleTest)
add_subdirectory( XrdCl )

add_subdirectory( common )
add_subdirectory( XrdClTests )
Expand Down
18 changes: 18 additions & 0 deletions 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::)
131 changes: 131 additions & 0 deletions tests/XrdCl/XrdClURL.cc
@@ -0,0 +1,131 @@
#undef NDEBUG

#include <XrdCl/XrdClURL.hh>
#include <gtest/gtest.h>

#include <climits>
#include <cstdlib>

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&param2=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&param2=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&param2=val2",
"root://@//path?param1=val1&param2=val2",
"root://:@//path?param1=val1&param2=val2",
"root://asd@://path?param1=val1&param2=val2"
"root://user1:passwd1host1:123//path?param1=val1&param2=val2",
"root://user1:passwd1@host1:asd//path?param1=val1&param2=val2",
};

for (const auto& url : invalid_urls)
EXPECT_FALSE(XrdCl::URL(url).IsValid()) << "URL " << url << " is not invalid" << std::endl;
}

197 changes: 0 additions & 197 deletions tests/XrdClTests/UtilsTest.cc
Expand Up @@ -24,7 +24,6 @@

#include <cppunit/extensions/HelperMacros.h>
#include "CppUnitXrdHelpers.hh"
#include "XrdCl/XrdClURL.hh"
#include "XrdCl/XrdClAnyObject.hh"
#include "XrdCl/XrdClTaskManager.hh"
#include "XrdCl/XrdClSIDManager.hh"
Expand All @@ -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();
Expand All @@ -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&param2=val2" );
XrdCl::URL url2( "root://user1@host1//path?param1=val1&param2=val2" );
XrdCl::URL url3( "root://host1" );
XrdCl::URL url4( "root://user1:passwd1@[::1]:123//path?param1=val1&param2=val2" );
XrdCl::URL url5( "root://user1@192.168.1.1:123//path?param1=val1&param2=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&param2=val2" );
XrdCl::URL urlInvalid2( "root://user1:passwd1host1:123//path?param1=val1&param2=val2" );
XrdCl::URL urlInvalid3( "root:////path?param1=val1&param2=val2" );
XrdCl::URL urlInvalid4( "root://@//path?param1=val1&param2=val2" );
XrdCl::URL urlInvalid5( "root://:@//path?param1=val1&param2=val2" );
XrdCl::URL urlInvalid6( "root://" );
XrdCl::URL urlInvalid7( "://asds" );
XrdCl::URL urlInvalid8( "root://asd@://path?param1=val1&param2=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&param2=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&param2=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&param2=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&param2=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:
Expand Down

0 comments on commit d596829

Please sign in to comment.