// server_parameters_test.cpp /** * Copyright (C) 2012 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #include "mongo/platform/basic.h" #include "mongo/unittest/unittest.h" #include "mongo/db/operation_context_noop.h" #include "mongo/db/server_parameters.h" namespace mongo { namespace { auto const getStr = [](ServerParameter& sp) { BSONObjBuilder b; sp.append(nullptr, b, "x"); return b.obj().firstElement().String(); }; auto const getInt = [](ServerParameter& sp) { BSONObjBuilder b; sp.append(nullptr, b, "x"); return b.obj().firstElement().Int(); }; auto const getBool = [](ServerParameter& sp) { BSONObjBuilder b; sp.append(nullptr, b, "x"); return b.obj().firstElement().Bool(); }; using std::string; using std::vector; TEST(ServerParameters, boundInt) { int ival = 123; BoundServerParameter bspi("bspl", [&ival](const int& v) { ival = v; return Status::OK(); }, [&ival] { return ival; }, ServerParameterType::kStartupOnly); ASSERT_EQUALS(123, getInt(bspi)); const struct { std::string setval; int expval; bool succeed; } setl[] = { {"234", 234, true}, {"5.5", -1, false}, {"345", 345, true}, {"flowers", -1, false}, {" 456", -1, false}, {" 567 ", -1, false}, {"678 ", -1, false}, {"789-0", -1, false}, }; for (auto const& p : setl) { ASSERT_EQ(bspi.setFromString(p.setval).isOK(), p.succeed); if (p.succeed) { ASSERT_EQUALS(p.expval, ival); ASSERT_EQUALS(p.expval, getInt(bspi)); } } } TEST(ServerParameter, boundBool) { bool bval = true; BoundServerParameter bspb("bspb", [&bval](const bool& v) { bval = v; return Status::OK(); }, [&bval] { return bval; }, ServerParameterType::kStartupOnly); ASSERT_TRUE(getBool(bspb)); struct { std::string setval; bool expval; bool succeed; } setb[] = { {"1", true, true}, {"0", false, true}, {"true", true, true}, {"false", false, true}, {"yes", false, false}, {"no", false, false}, {"", false, false}, {"-1", false, false}, }; for (auto const& p : setb) { ASSERT_EQ(bspb.setFromString(p.setval).isOK(), p.succeed); if (p.succeed) { ASSERT_EQUALS(p.expval, bval); ASSERT_EQUALS(p.expval, getBool(bspb)); } } } TEST(ServerParameters, boundStringExplicitLock) { stdx::mutex mut; std::string value("initial"); BoundServerParameter bspsel("bsp", [&value, &mut](const std::string& v) { stdx::unique_lock lk(mut); value = v; return Status::OK(); }, [&value, &mut] { stdx::unique_lock lk(mut); return value; }); ASSERT_EQUALS("initial", getStr(bspsel)); const std::string sets[] = {"first-set", "second-set", "third-set"}; for (auto const& p : sets) { ASSERT_TRUE(bspsel.set(BSON("x" << p).firstElement()).isOK()); ASSERT_EQUALS(p, getStr(bspsel)); } } TEST(ServerParameters, boundIntLock) { LockedServerParameter bspi("lsp", 1234); ASSERT_EQUALS(1234, getInt(bspi)); ASSERT_EQUALS(1234, bspi.getLocked()); std::ostringstream maxint; maxint << std::numeric_limits::max(); std::ostringstream lowint; lowint << (std::numeric_limits::lowest() + 1); std::ostringstream toobig; toobig << std::numeric_limits::max() << "0"; std::ostringstream toosmall; toosmall << std::numeric_limits::lowest() << "0"; const struct { std::string setstr; int setint; bool succeed; } sets[] = { {"5678", 5678, true}, {"67", 67, true}, {maxint.str(), std::numeric_limits::max(), true}, {lowint.str(), std::numeric_limits::lowest() + 1, true}, {toobig.str(), -1, false}, {toosmall.str(), -1, false}, {"flowers", -1, false}, {"123.456", -1, false}, {"123-456", -1, false}, {" 123", -1, false}, {" 123 ", -1, false}, {"123 ", -1, false}, }; for (auto const& p : sets) { ASSERT_EQ(bspi.setFromString(p.setstr).isOK(), p.succeed); if (p.succeed) { ASSERT_EQUALS(p.setint, getInt(bspi)); ASSERT_EQUALS(p.setint, bspi.getLocked()); } } const int seti[] = { -1, 0, 1, std::numeric_limits::lowest() + 1, std::numeric_limits::max()}; for (auto const& p : seti) { ASSERT_TRUE(bspi.setLocked(p).isOK()); ASSERT_EQUALS(p, getInt(bspi)); ASSERT_EQUALS(p, bspi.getLocked()); } } TEST(ServerParameters, Simple1) { AtomicInt32 f(5); ExportedServerParameter ff(NULL, "ff", &f); ASSERT_EQUALS("ff", ff.name()); ASSERT_TRUE(ff.set(6).isOK()); ASSERT_EQUALS(6, f.load()); ASSERT_TRUE(ff.set(BSON("x" << 7).firstElement()).isOK()); ASSERT_EQUALS(7, f.load()); ASSERT_TRUE(ff.setFromString("8").isOK()); ASSERT_EQUALS(8, f.load()); } TEST(ServerParameters, Vector1) { vector v; ExportedServerParameter, ServerParameterType::kStartupOnly> vv(NULL, "vv", &v); BSONObj x = BSON("x" << BSON_ARRAY("a" << "b" << "c")); ASSERT_TRUE(vv.set(x.firstElement()).isOK()); ASSERT_EQUALS(3U, v.size()); ASSERT_EQUALS("a", v[0]); ASSERT_EQUALS("b", v[1]); ASSERT_EQUALS("c", v[2]); BSONObjBuilder b; OperationContextNoop opCtx; vv.append(&opCtx, b, vv.name()); BSONObj y = b.obj(); ASSERT(x.firstElement().woCompare(y.firstElement(), false) == 0); ASSERT_TRUE(vv.setFromString("d,e").isOK()); ASSERT_EQUALS(2U, v.size()); ASSERT_EQUALS("d", v[0]); ASSERT_EQUALS("e", v[1]); } TEST(ServerParameters, Validators) { AtomicInt32 myVal(0); ExportedServerParameter myParam( nullptr, "myVal", &myVal); myParam.withValidator([](const int& newVal) { if (newVal < 0) { return Status(ErrorCodes::BadValue, "Must be positive"); } return Status::OK(); }); ASSERT_OK(myParam.set(10)); ASSERT_EQUALS(10, myVal.load()); ASSERT_EQUALS(ErrorCodes::BadValue, myParam.set(-1)); ASSERT_EQUALS(10, myVal.load()); } MONGO_EXPORT_SERVER_PARAMETER(oddTestParameter, int, 123) ->withValidator([](const int& newVal) { if ((newVal & 1) == 0) { return Status(ErrorCodes::BadValue, "must be odd"); } return Status::OK(); }); } // namespace } // namespace mongo