377 lines
10 KiB
C++
377 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
*
|
|
* Change Date: 2024-11-16
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2 or later of the General
|
|
* Public License.
|
|
*/
|
|
|
|
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
|
#ifndef SS_DEBUG
|
|
#define SS_DEBUG
|
|
#endif
|
|
|
|
#include <iostream>
|
|
#include <maxbase/log.hh>
|
|
#include <maxscale/config2.hh>
|
|
#include "../internal/server.hh"
|
|
#include "test_utils.hh"
|
|
|
|
using namespace std;
|
|
|
|
inline ostream& operator<<(ostream& out, const std::chrono::seconds& x)
|
|
{
|
|
out << x.count();
|
|
return out;
|
|
}
|
|
|
|
inline ostream& operator<<(ostream& out, const std::chrono::milliseconds& x)
|
|
{
|
|
out << x.count();
|
|
return out;
|
|
}
|
|
|
|
config::Specification specification("test_module", config::Specification::FILTER);
|
|
|
|
config::ParamBool
|
|
param_bool(&specification,
|
|
"boolean_parameter",
|
|
"Specifies whether something is enabled.");
|
|
|
|
config::ParamCount
|
|
param_count(&specification,
|
|
"count_parameter",
|
|
"Specifies the cardinality of something.");
|
|
|
|
config::ParamDuration<std::chrono::seconds>
|
|
param_duration_1(&specification,
|
|
"duration_parameter_1",
|
|
"Specifies the duration of something.",
|
|
mxs::config::INTERPRET_AS_SECONDS);
|
|
|
|
config::ParamDuration<std::chrono::milliseconds>
|
|
param_duration_2(&specification,
|
|
"duration_parameter_2",
|
|
"Specifies the duration of something.",
|
|
mxs::config::INTERPRET_AS_MILLISECONDS);
|
|
|
|
enum Enum
|
|
{
|
|
ENUM_ONE,
|
|
ENUM_TWO
|
|
};
|
|
|
|
config::ParamEnum<Enum>
|
|
param_enum(&specification,
|
|
"enum_parameter",
|
|
"Specifies a range of values.",
|
|
{
|
|
{ENUM_ONE, "one"},
|
|
{ENUM_TWO, "two"}
|
|
});
|
|
|
|
config::ParamInteger
|
|
param_integer(&specification,
|
|
"integer_parameter",
|
|
"Specifies a number.");
|
|
|
|
config::ParamPath
|
|
param_path(&specification,
|
|
"path_parameter",
|
|
"Specifies the path of something.",
|
|
config::ParamPath::F);
|
|
|
|
config::ParamServer
|
|
param_server(&specification,
|
|
"server_parameter",
|
|
"Specifies a server.");
|
|
|
|
config::ParamSize
|
|
param_size(&specification,
|
|
"size_parameter",
|
|
"Specifies the size of something.");
|
|
|
|
config::ParamString
|
|
param_string(&specification,
|
|
"string_parameter",
|
|
"Specifies the name of something.");
|
|
|
|
template<class T>
|
|
struct TestEntry
|
|
{
|
|
const char* zText;
|
|
bool valid;
|
|
T value;
|
|
};
|
|
|
|
#define elements_in_array(x) (sizeof(x) / sizeof(x[0]))
|
|
|
|
template<class T>
|
|
int test(T& value, const TestEntry<typename T::value_type>* pEntries, int nEntries)
|
|
{
|
|
const config::Param& param = value.parameter();
|
|
|
|
cout << "Testing " << param.type() << " parameter " << param.name() << "." << endl;
|
|
|
|
int nErrors = 0;
|
|
|
|
for (int i = 0; i < nEntries; ++i)
|
|
{
|
|
const auto& entry = pEntries[i];
|
|
|
|
std::string message;
|
|
bool validated = param.validate(entry.zText, &message);
|
|
|
|
if (entry.valid && validated)
|
|
{
|
|
param.set(value, entry.zText);
|
|
|
|
if (value != entry.value)
|
|
{
|
|
cout << value.to_string() << " != " << entry.value << endl;
|
|
++nErrors;
|
|
}
|
|
}
|
|
else if (entry.valid && !validated)
|
|
{
|
|
cout << "Expected \"" << entry.zText << "\" to BE valid for " << param.type()
|
|
<< " parameter " << param.name() << ", but it was NOT validated: " << message << endl;
|
|
++nErrors;
|
|
}
|
|
else if (!entry.valid && validated)
|
|
{
|
|
cout << "Expected \"" << entry.zText << "\" NOT to be valid for " << param.type()
|
|
<< " parameter " << param.name() << ", but it WAS validated." << endl;
|
|
++nErrors;
|
|
}
|
|
}
|
|
|
|
return nErrors;
|
|
}
|
|
|
|
int test_bool(config::Bool& value)
|
|
{
|
|
static const TestEntry<config::Bool::value_type> entries[] =
|
|
{
|
|
{"1", true, true },
|
|
{"0", true, false},
|
|
{"true", true, true },
|
|
{"false", true, false},
|
|
{"on", true, true },
|
|
{"off", true, false},
|
|
|
|
{"2", false},
|
|
{"truth", false},
|
|
{"%&", false},
|
|
{"-1", false},
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_count(config::Count& value)
|
|
{
|
|
static const TestEntry<config::Count::value_type> entries[] =
|
|
{
|
|
{"1", true, 1 },
|
|
{"9999", true, 9999},
|
|
{"0", true, 0 },
|
|
|
|
{"0x45", false},
|
|
{"blah", false},
|
|
{"-1", false},
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_duration(config::Duration<std::chrono::seconds>& value)
|
|
{
|
|
static const TestEntry<config::Duration<std::chrono::seconds>::value_type> entries[] =
|
|
{
|
|
{"1", true, std::chrono::seconds {1 }},
|
|
{"1ms", true, std::chrono::seconds {0 }},
|
|
{"1s", true, std::chrono::seconds {1 }},
|
|
{"1m", true, std::chrono::seconds {60 }},
|
|
{"1h", true, std::chrono::seconds {3600}},
|
|
|
|
{"1x", false},
|
|
{"a", false},
|
|
{"-", false},
|
|
{"second", false}
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_duration(config::Duration<std::chrono::milliseconds>& value)
|
|
{
|
|
static const TestEntry<config::Duration<std::chrono::milliseconds>::value_type> entries[] =
|
|
{
|
|
{"1", true, std::chrono::milliseconds {1 }},
|
|
{"1ms", true, std::chrono::milliseconds {1 }},
|
|
{"1s", true, std::chrono::milliseconds {1000 }},
|
|
{"1m", true, std::chrono::milliseconds {60000 }},
|
|
{"1h", true, std::chrono::milliseconds {3600000}},
|
|
|
|
{"1x", false},
|
|
{"a", false},
|
|
{"-", false},
|
|
{"second", false}
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_enum(config::Enum<Enum>& value)
|
|
{
|
|
static const TestEntry<Enum> entries[] =
|
|
{
|
|
{"one", true, ENUM_ONE},
|
|
{"two", true, ENUM_TWO},
|
|
|
|
{"blah", false},
|
|
{"1", false},
|
|
{"ones", false}
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_integer(config::Integer& value)
|
|
{
|
|
static const TestEntry<config::Integer::value_type> entries[] =
|
|
{
|
|
{"0", true, 0 },
|
|
{"-1", true, -1 },
|
|
{"1", true, 1 },
|
|
{"-2147483648", true, -2147483648},
|
|
{"2147483647", true, 2147483647 },
|
|
|
|
{"-2147483649", false},
|
|
{"2147483648", false},
|
|
{"0x10", false},
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_path(config::Path& value)
|
|
{
|
|
static char path[PATH_MAX];
|
|
static char* strpath = getcwd(path, sizeof(path));
|
|
|
|
static const TestEntry<config::Path::value_type> entries[] =
|
|
{
|
|
{strpath, true, strpath},
|
|
{"/tmp", true, "/tmp" },
|
|
|
|
{"non-existent", false}
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_server(config::Server& value)
|
|
{
|
|
MXS_CONFIG_PARAMETER params1;
|
|
params1.set(CN_PROTOCOL, "mariadbbackend");
|
|
params1.set(CN_PERSISTMAXTIME, "0");
|
|
params1.set(CN_RANK, "primary");
|
|
|
|
std::unique_ptr<Server> sServer1(Server::server_alloc("TheServer1", params1));
|
|
mxb_assert(sServer1.get());
|
|
|
|
const TestEntry<config::Server::value_type> entries[] =
|
|
{
|
|
{ "TheServer1", true, sServer1.get() },
|
|
{ "TheServer0", false },
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_size(config::Size& value)
|
|
{
|
|
static const TestEntry<config::Size::value_type> entries[] =
|
|
{
|
|
{"0", true, 0 },
|
|
{"100", true, 100},
|
|
|
|
{"-100", false},
|
|
{"0x100", false},
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int test_string(config::String& value)
|
|
{
|
|
static const TestEntry<config::String::value_type> entries[] =
|
|
{
|
|
{"blah", true, "blah" },
|
|
{"\"blah\"", true, "blah" },
|
|
{"'blah'", true, "blah" },
|
|
{"123", true, "123" },
|
|
{"`blah`", true, "`blah`"},
|
|
|
|
{"'blah\"", false}
|
|
};
|
|
|
|
return test(value, entries, elements_in_array(entries));
|
|
}
|
|
|
|
int main()
|
|
{
|
|
init_test_env();
|
|
|
|
for_each(specification.cbegin(), specification.cend(), [](const config::Specification::value_type& p) {
|
|
cout << p.second->documentation() << endl;
|
|
});
|
|
|
|
cout << endl;
|
|
|
|
specification.document(cout);
|
|
|
|
config::Configuration configuration("test", &specification);
|
|
|
|
int nErrors = 0;
|
|
|
|
config::Bool value_bool(&configuration, ¶m_bool);
|
|
nErrors += test_bool(value_bool);
|
|
|
|
config::Count value_count(&configuration, ¶m_count);
|
|
nErrors += test_count(value_count);
|
|
|
|
config::Duration<std::chrono::seconds> value_duration_1(&configuration, ¶m_duration_1);
|
|
nErrors += test_duration(value_duration_1);
|
|
|
|
config::Duration<std::chrono::milliseconds> value_duration_2(&configuration, ¶m_duration_2);
|
|
nErrors += test_duration(value_duration_2);
|
|
|
|
config::Enum<Enum> value_enum(&configuration, ¶m_enum);
|
|
nErrors += test_enum(value_enum);
|
|
|
|
config::Integer value_integer(&configuration, ¶m_integer);
|
|
nErrors += test_integer(value_integer);
|
|
|
|
config::Path value_path(&configuration, ¶m_path);
|
|
nErrors += test_path(value_path);
|
|
|
|
config::Server value_server(&configuration, ¶m_server);
|
|
nErrors += test_server(value_server);
|
|
|
|
config::Size value_size(&configuration, ¶m_size);
|
|
nErrors += test_size(value_size);
|
|
|
|
config::String value_string(&configuration, ¶m_string);
|
|
nErrors += test_string(value_string);
|
|
|
|
return nErrors ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|