1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <mutex> 18 #include <string> 19 #include <string_view> 20 #include <unordered_map> 21 22 #include <android-base/format.h> 23 #include <android-base/stringprintf.h> 24 #include <android-base/test_utils.h> 25 #include <gmock/gmock.h> 26 #include <gtest/gtest.h> 27 28 #include "Experiments.h" 29 30 namespace android::net { 31 32 class ExperimentsTest : public ::testing::Test { 33 public: 34 ExperimentsTest() : mExperiments(fakeGetExperimentFlagInt) {} 35 36 protected: 37 static int fakeGetExperimentFlagInt(const std::string& key, int defaultValue) { 38 auto it = sFakeFlagsMapInt.find(key); 39 if (it != sFakeFlagsMapInt.end()) { 40 return it->second; 41 } 42 return defaultValue; 43 } 44 45 void setupFakeMap(int value) { 46 for (const auto& key : Experiments::kExperimentFlagKeyList) { 47 sFakeFlagsMapInt[key] = value; 48 } 49 } 50 51 void setupExperimentsMap(int value) { 52 setupFakeMap(value); 53 std::lock_guard guard(mExperiments.mMutex); 54 mExperiments.mFlagsMapInt = sFakeFlagsMapInt; 55 } 56 57 void expectFlagsMapInt() { 58 std::lock_guard guard(mExperiments.mMutex); 59 EXPECT_THAT(mExperiments.mFlagsMapInt, ::testing::ContainerEq(sFakeFlagsMapInt)); 60 } 61 62 void expectFlagsMapIntDefault() { 63 std::lock_guard guard(mExperiments.mMutex); 64 for (const auto& [key, value] : mExperiments.mFlagsMapInt) { 65 EXPECT_EQ(value, Experiments::kFlagIntDefault); 66 } 67 } 68 69 void expectGetDnsExperimentFlagIntDefault(int value) { 70 for (const auto& key : Experiments::kExperimentFlagKeyList) { 71 EXPECT_EQ(mExperiments.getFlag(key, value), value); 72 } 73 } 74 75 void expectGetDnsExperimentFlagInt() { 76 std::unordered_map<std::string_view, int> tempMap; 77 for (const auto& key : Experiments::kExperimentFlagKeyList) { 78 tempMap[key] = mExperiments.getFlag(key, 0); 79 } 80 EXPECT_THAT(tempMap, ::testing::ContainerEq(sFakeFlagsMapInt)); 81 } 82 83 void expectDumpOutput() { 84 netdutils::DumpWriter dw(STDOUT_FILENO); 85 CapturedStdout captured; 86 mExperiments.dump(dw); 87 const std::string dumpString = captured.str(); 88 const std::string title = "Experiments list:"; 89 EXPECT_EQ(dumpString.find(title), 0U); 90 size_t startPos = title.size(); 91 std::lock_guard guard(mExperiments.mMutex); 92 for (const auto& [key, value] : mExperiments.mFlagsMapInt) { 93 std::string flagDump = fmt::format("{}: {}", key, value); 94 if (value == Experiments::kFlagIntDefault) { 95 flagDump = fmt::format("{}: UNSET", key); 96 } 97 SCOPED_TRACE(flagDump); 98 size_t pos = dumpString.find(flagDump, startPos); 99 EXPECT_NE(pos, std::string::npos); 100 startPos = pos + flagDump.size(); 101 } 102 EXPECT_EQ(startPos + 1, dumpString.size()); 103 EXPECT_EQ(dumpString.substr(startPos), "\n"); 104 } 105 106 static std::unordered_map<std::string_view, int> sFakeFlagsMapInt; 107 Experiments mExperiments; 108 }; 109 110 std::unordered_map<std::string_view, int> ExperimentsTest::sFakeFlagsMapInt; 111 112 TEST_F(ExperimentsTest, update) { 113 std::vector<int> testValues = {50, 3, 5, 0}; 114 for (int testValue : testValues) { 115 setupFakeMap(testValue); 116 mExperiments.update(); 117 expectFlagsMapInt(); 118 } 119 } 120 121 TEST_F(ExperimentsTest, getDnsExperimentFlagInt) { 122 std::vector<int> testValues = {5, 1, 6, 0}; 123 for (int testValue : testValues) { 124 setupExperimentsMap(testValue); 125 expectGetDnsExperimentFlagInt(); 126 } 127 } 128 129 TEST_F(ExperimentsTest, getDnsExperimentFlagIntDefaultValue) { 130 // Clear the map and make mExperiments initialized with our default int value. 131 sFakeFlagsMapInt.clear(); 132 mExperiments.update(); 133 expectFlagsMapIntDefault(); 134 std::vector<int> testValues = {100, 50, 30, 5}; 135 for (int testValue : testValues) { 136 expectGetDnsExperimentFlagIntDefault(testValue); 137 } 138 } 139 140 TEST_F(ExperimentsTest, dump) { 141 std::vector<int> testValues = {100, 37, 0, 30}; 142 for (int testValue : testValues) { 143 setupFakeMap(testValue); 144 mExperiments.update(); 145 expectDumpOutput(); 146 } 147 sFakeFlagsMapInt.clear(); 148 mExperiments.update(); 149 expectDumpOutput(); 150 } 151 152 } // namespace android::net 153