TestPACMan.cpp (7380B)
1 #include <utility> 2 3 #include "gtest/gtest.h" 4 #include "nsServiceManagerUtils.h" 5 #include "../../../xpcom/threads/nsThreadManager.h" 6 #include "nsIDHCPClient.h" 7 #include "mozilla/Preferences.h" 8 #include "nsComponentManager.h" 9 #include "nsIPrefService.h" 10 #include "nsNetCID.h" 11 #include "mozilla/ModuleUtils.h" 12 #include "mozilla/GenericFactory.h" 13 #include "../../base/nsPACMan.h" 14 #include "mozilla/StaticMutex.h" 15 16 #define TEST_WPAD_DHCP_OPTION "http://pac/pac.dat" 17 #define TEST_ASSIGNED_PAC_URL "http://assignedpac/pac.dat" 18 #define WPAD_PREF 4 19 #define NETWORK_PROXY_TYPE_PREF_NAME "network.proxy.type" 20 #define GETTING_NETWORK_PROXY_TYPE_FAILED (-1) 21 22 static mozilla::StaticMutex sMutex; 23 constinit nsCString WPADOptionResult MOZ_GUARDED_BY(sMutex); 24 25 namespace mozilla { 26 namespace net { 27 28 nsresult SetNetworkProxyType(int32_t pref) { 29 return Preferences::SetInt(NETWORK_PROXY_TYPE_PREF_NAME, pref); 30 } 31 32 nsresult GetNetworkProxyType(int32_t* pref) { 33 return Preferences::GetInt(NETWORK_PROXY_TYPE_PREF_NAME, pref); 34 } 35 36 class nsTestDHCPClient final : public nsIDHCPClient { 37 public: 38 NS_DECL_THREADSAFE_ISUPPORTS 39 NS_DECL_NSIDHCPCLIENT 40 41 nsTestDHCPClient() = default; 42 43 nsresult Init() { return NS_OK; }; 44 45 private: 46 ~nsTestDHCPClient() = default; 47 }; 48 49 NS_IMETHODIMP 50 nsTestDHCPClient::GetOption(uint8_t option, nsACString& _retval) { 51 mozilla::StaticMutexAutoLock lock(sMutex); 52 _retval.Assign(WPADOptionResult); 53 return NS_OK; 54 } 55 56 NS_IMPL_ISUPPORTS(nsTestDHCPClient, nsIDHCPClient) 57 58 #define NS_TESTDHCPCLIENTSERVICE_CID /* {FEBF1D69-4D7D-4891-9524-045AD18B5593} \ 59 */ \ 60 {0xFEBF1D69, 0x4D7D, 0x4891, {0x95, 0x24, 0x04, 0x5a, 0xd1, 0x8b, 0x55, 0x93}} 61 62 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsTestDHCPClient, Init) 63 NS_DEFINE_NAMED_CID(NS_TESTDHCPCLIENTSERVICE_CID); 64 65 void SetOptionResult(const char* result) { 66 mozilla::StaticMutexAutoLock lock(sMutex); 67 WPADOptionResult.Assign(result); 68 } 69 70 class ProcessPendingEventsAction final : public Runnable { 71 public: 72 ProcessPendingEventsAction() : Runnable("net::ProcessPendingEventsAction") {} 73 74 NS_IMETHOD 75 Run() override { 76 if (NS_HasPendingEvents(nullptr)) { 77 NS_WARNING("Found pending requests on PAC thread"); 78 nsresult rv; 79 rv = NS_ProcessPendingEvents(nullptr); 80 EXPECT_EQ(NS_OK, rv); 81 } 82 NS_WARNING("No pending requests on PAC thread"); 83 return NS_OK; 84 } 85 }; 86 87 class TestPACMan : public ::testing::Test { 88 protected: 89 RefPtr<nsPACMan> mPACMan; 90 91 void ProcessAllEvents() { 92 ProcessPendingEventsOnPACThread(); 93 nsresult rv; 94 while (NS_HasPendingEvents(nullptr)) { 95 NS_WARNING("Pending events on main thread"); 96 rv = NS_ProcessPendingEvents(nullptr); 97 ASSERT_EQ(NS_OK, rv); 98 ProcessPendingEventsOnPACThread(); 99 } 100 NS_WARNING("End of pending events on main thread"); 101 } 102 103 // This method is used to ensure that all pending events on the main thread 104 // and the Proxy thread are processsed. 105 // It iterates over ProcessAllEvents because simply calling ProcessAllEvents 106 // once did not reliably process the events on both threads on all platforms. 107 void ProcessAllEventsTenTimes() { 108 for (int i = 0; i < 10; i++) { 109 ProcessAllEvents(); 110 } 111 } 112 113 virtual void SetUp() { 114 Preferences::SetBool("network.proxy.dhcp_wpad_only_one_outstanding", false); 115 Preferences::SetFloat("network.proxy.dhcp_wpad_timeout_sec", 30); 116 ASSERT_EQ(NS_OK, GetNetworkProxyType(&originalNetworkProxyTypePref)); 117 nsCOMPtr<nsIFactory> factory; 118 nsresult rv = nsComponentManagerImpl::gComponentManager->GetClassObject( 119 kNS_TESTDHCPCLIENTSERVICE_CID, NS_GET_IID(nsIFactory), 120 getter_AddRefs(factory)); 121 if (NS_SUCCEEDED(rv) && factory) { 122 rv = nsComponentManagerImpl::gComponentManager->UnregisterFactory( 123 kNS_TESTDHCPCLIENTSERVICE_CID, factory); 124 ASSERT_EQ(NS_OK, rv); 125 } 126 factory = new mozilla::GenericFactory(nsTestDHCPClientConstructor); 127 nsComponentManagerImpl::gComponentManager->RegisterFactory( 128 kNS_TESTDHCPCLIENTSERVICE_CID, "nsTestDHCPClient", 129 NS_DHCPCLIENT_CONTRACTID, factory); 130 131 mPACMan = new nsPACMan(nullptr); 132 mPACMan->SetWPADOverDHCPEnabled(true); 133 mPACMan->Init(nullptr); 134 ASSERT_EQ(NS_OK, SetNetworkProxyType(WPAD_PREF)); 135 } 136 137 virtual void TearDown() { 138 mPACMan->Shutdown(); 139 if (originalNetworkProxyTypePref != GETTING_NETWORK_PROXY_TYPE_FAILED) { 140 ASSERT_EQ(NS_OK, SetNetworkProxyType(originalNetworkProxyTypePref)); 141 } 142 } 143 144 nsCOMPtr<nsIDHCPClient> GetPACManDHCPCient() { return mPACMan->mDHCPClient; } 145 146 void SetPACManDHCPCient(nsCOMPtr<nsIDHCPClient> aValue) { 147 mPACMan->mDHCPClient = std::move(aValue); 148 } 149 150 void AssertPACSpecEqualTo(const char* aExpected) { 151 ASSERT_STREQ(aExpected, mPACMan->mPACURISpec.Data()); 152 } 153 154 private: 155 int32_t originalNetworkProxyTypePref = GETTING_NETWORK_PROXY_TYPE_FAILED; 156 157 void ProcessPendingEventsOnPACThread() { 158 RefPtr<ProcessPendingEventsAction> action = 159 new ProcessPendingEventsAction(); 160 161 mPACMan->DispatchToPAC(action.forget(), /*aSync =*/true); 162 } 163 }; 164 165 TEST_F(TestPACMan, TestCreateDHCPClientAndGetOption) { 166 SetOptionResult(TEST_WPAD_DHCP_OPTION); 167 nsCString spec; 168 169 GetPACManDHCPCient()->GetOption(252, spec); 170 171 ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, spec.Data()); 172 } 173 174 TEST_F(TestPACMan, TestCreateDHCPClientAndGetEmptyOption) { 175 SetOptionResult(""); 176 nsCString spec; 177 spec.AssignLiteral(TEST_ASSIGNED_PAC_URL); 178 179 GetPACManDHCPCient()->GetOption(252, spec); 180 181 ASSERT_TRUE(spec.IsEmpty()); 182 } 183 184 TEST_F(TestPACMan, 185 WhenTheDHCPClientExistsAndDHCPIsNonEmptyDHCPOptionIsUsedAsPACUri) { 186 SetOptionResult(TEST_WPAD_DHCP_OPTION); 187 188 mPACMan->LoadPACFromURI(""_ns); 189 ProcessAllEventsTenTimes(); 190 191 mozilla::StaticMutexAutoLock lock(sMutex); 192 ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, WPADOptionResult.Data()); 193 AssertPACSpecEqualTo(TEST_WPAD_DHCP_OPTION); 194 } 195 196 TEST_F(TestPACMan, WhenTheDHCPResponseIsEmptyWPADDefaultsToStandardURL) { 197 SetOptionResult(""_ns.Data()); 198 199 mPACMan->LoadPACFromURI(""_ns); 200 ASSERT_TRUE(NS_HasPendingEvents(nullptr)); 201 ProcessAllEventsTenTimes(); 202 203 mozilla::StaticMutexAutoLock lock(sMutex); 204 ASSERT_STREQ("", WPADOptionResult.Data()); 205 AssertPACSpecEqualTo("http://wpad/wpad.dat"); 206 } 207 208 TEST_F(TestPACMan, WhenThereIsNoDHCPClientWPADDefaultsToStandardURL) { 209 SetOptionResult(TEST_WPAD_DHCP_OPTION); 210 SetPACManDHCPCient(nullptr); 211 212 mPACMan->LoadPACFromURI(""_ns); 213 ProcessAllEventsTenTimes(); 214 215 mozilla::StaticMutexAutoLock lock(sMutex); 216 ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, WPADOptionResult.Data()); 217 AssertPACSpecEqualTo("http://wpad/wpad.dat"); 218 } 219 220 TEST_F(TestPACMan, WhenWPADOverDHCPIsPreffedOffWPADDefaultsToStandardURL) { 221 SetOptionResult(TEST_WPAD_DHCP_OPTION); 222 mPACMan->SetWPADOverDHCPEnabled(false); 223 224 mPACMan->LoadPACFromURI(""_ns); 225 ProcessAllEventsTenTimes(); 226 227 mozilla::StaticMutexAutoLock lock(sMutex); 228 ASSERT_STREQ(TEST_WPAD_DHCP_OPTION, WPADOptionResult.Data()); 229 AssertPACSpecEqualTo("http://wpad/wpad.dat"); 230 } 231 232 TEST_F(TestPACMan, WhenPACUriIsSetDirectlyItIsUsedRatherThanWPAD) { 233 SetOptionResult(TEST_WPAD_DHCP_OPTION); 234 nsCString spec; 235 spec.AssignLiteral(TEST_ASSIGNED_PAC_URL); 236 237 mPACMan->LoadPACFromURI(spec); 238 ProcessAllEventsTenTimes(); 239 240 AssertPACSpecEqualTo(TEST_ASSIGNED_PAC_URL); 241 } 242 243 } // namespace net 244 } // namespace mozilla