Home | History | Annotate | Download | only in chromeos
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/proxy_config_service_impl.h"
      6 
      7 #include <map>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/format_macros.h"
     12 #include "base/logging.h"
     13 #include "base/string_util.h"
     14 #include "base/stringprintf.h"
     15 #include "chrome/browser/chromeos/cros/cros_library.h"
     16 #include "content/browser/browser_thread.h"
     17 #include "content/common/json_value_serializer.h"
     18 #include "net/proxy/proxy_config_service_common_unittest.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 #include "testing/platform_test.h"
     21 
     22 namespace chromeos {
     23 
     24 namespace {
     25 
     26 struct Input {  // Fields of chromeos::ProxyConfigServiceImpl::ProxyConfig.
     27   ProxyConfigServiceImpl::ProxyConfig::Mode mode;
     28   const char* pac_url;
     29   const char* single_uri;
     30   const char* http_uri;
     31   const char* https_uri;
     32   const char* ftp_uri;
     33   const char* socks_uri;
     34   const char* bypass_rules;
     35 };
     36 
     37 // Builds an identifier for each test in an array.
     38 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
     39 
     40 // Shortcuts to declare enums within chromeos's ProxyConfig.
     41 #define MK_MODE(mode) ProxyConfigServiceImpl::ProxyConfig::MODE_##mode
     42 #define MK_SRC(src) ProxyConfigServiceImpl::ProxyConfig::SOURCE_##src
     43 #define MK_SCHM(scheme) net::ProxyServer::SCHEME_##scheme
     44 
     45 // Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
     46 const struct {
     47   // Short description to identify the test
     48   std::string description;
     49 
     50   bool is_valid;
     51   bool test_read_write_access;
     52 
     53   Input input;
     54 
     55   // Expected outputs from fields of net::ProxyConfig (via IO).
     56   bool auto_detect;
     57   GURL pac_url;
     58   net::ProxyRulesExpectation proxy_rules;
     59 } tests[] = {
     60   {
     61     TEST_DESC("No proxying"),
     62 
     63     true,  // is_valid
     64     true,  // test_read_write_access
     65 
     66     { // Input.
     67       MK_MODE(DIRECT),  // mode
     68     },
     69 
     70     // Expected result.
     71     false,                                   // auto_detect
     72     GURL(),                                  // pac_url
     73     net::ProxyRulesExpectation::Empty(),     // proxy_rules
     74   },
     75 
     76   {
     77     TEST_DESC("Auto detect"),
     78 
     79     true,  // is_valid
     80     true,  // test_read_write_access
     81 
     82     { // Input.
     83       MK_MODE(AUTO_DETECT),  // mode
     84     },
     85 
     86     // Expected result.
     87     true,                                    // auto_detect
     88     GURL(),                                  // pac_url
     89     net::ProxyRulesExpectation::Empty(),     // proxy_rules
     90   },
     91 
     92   {
     93     TEST_DESC("Valid PAC URL"),
     94 
     95     true,  // is_valid
     96     true,  // test_read_write_access
     97 
     98     { // Input.
     99       MK_MODE(PAC_SCRIPT),     // mode
    100       "http://wpad/wpad.dat",  // pac_url
    101     },
    102 
    103     // Expected result.
    104     false,                                   // auto_detect
    105     GURL("http://wpad/wpad.dat"),            // pac_url
    106     net::ProxyRulesExpectation::Empty(),     // proxy_rules
    107   },
    108 
    109   {
    110     TEST_DESC("Invalid PAC URL"),
    111 
    112     false,  // is_valid
    113     false,  // test_read_write_access
    114 
    115     { // Input.
    116       MK_MODE(PAC_SCRIPT),  // mode
    117       "wpad.dat",           // pac_url
    118     },
    119 
    120     // Expected result.
    121     false,                                   // auto_detect
    122     GURL(),                                  // pac_url
    123     net::ProxyRulesExpectation::Empty(),     // proxy_rules
    124   },
    125 
    126   {
    127     TEST_DESC("Single-host in proxy list"),
    128 
    129     true,  // is_valid
    130     true,  // test_read_write_access
    131 
    132     { // Input.
    133       MK_MODE(SINGLE_PROXY),  // mode
    134       NULL,                   // pac_url
    135       "www.google.com",       // single_uri
    136     },
    137 
    138     // Expected result.
    139     false,                                   // auto_detect
    140     GURL(),                                  // pac_url
    141     net::ProxyRulesExpectation::Single(      // proxy_rules
    142         "www.google.com:80",  // single proxy
    143         ""),                  // bypass rules
    144   },
    145 
    146   {
    147     TEST_DESC("Single-host, different port"),
    148 
    149     true,   // is_valid
    150     false,  // test_read_write_access
    151 
    152     { // Input.
    153       MK_MODE(SINGLE_PROXY),  // mode
    154       NULL,                   // pac_url
    155       "www.google.com:99",    // single_uri
    156     },
    157 
    158     // Expected result.
    159     false,                                   // auto_detect
    160     GURL(),                                  // pac_url
    161     net::ProxyRulesExpectation::Single(      // proxy_rules
    162         "www.google.com:99",  // single
    163         ""),                  // bypass rules
    164   },
    165 
    166   {
    167     TEST_DESC("Tolerate a scheme"),
    168 
    169     true,   // is_valid
    170     false,  // test_read_write_access
    171 
    172     { // Input.
    173       MK_MODE(SINGLE_PROXY),       // mode
    174       NULL,                        // pac_url
    175       "http://www.google.com:99",  // single_uri
    176     },
    177 
    178     // Expected result.
    179     false,                                   // auto_detect
    180     GURL(),                                  // pac_url
    181     net::ProxyRulesExpectation::Single(      // proxy_rules
    182         "www.google.com:99",  // single proxy
    183         ""),                  // bypass rules
    184   },
    185 
    186   {
    187     TEST_DESC("Per-scheme proxy rules"),
    188 
    189     true,  // is_valid
    190     true,  // test_read_write_access
    191 
    192     { // Input.
    193       MK_MODE(PROXY_PER_SCHEME),  // mode
    194       NULL,                       // pac_url
    195       NULL,                       // single_uri
    196       "www.google.com:80",        // http_uri
    197       "www.foo.com:110",          // https_uri
    198       "ftp.foo.com:121",          // ftp_uri
    199       "socks.com:888",            // socks_uri
    200     },
    201 
    202     // Expected result.
    203     false,                          // auto_detect
    204     GURL(),                         // pac_url
    205     net::ProxyRulesExpectation::PerSchemeWithSocks(  // proxy_rules
    206         "www.google.com:80",        // http
    207         "https://www.foo.com:110",  // https
    208         "ftp.foo.com:121",          // ftp
    209         "socks5://socks.com:888",   // fallback proxy
    210         ""),                        // bypass rules
    211   },
    212 
    213   {
    214     TEST_DESC("Bypass rules"),
    215 
    216     true,  // is_valid
    217     true,  // test_read_write_access
    218 
    219     { // Input.
    220       MK_MODE(SINGLE_PROXY),      // mode
    221       NULL,                       // pac_url
    222       "www.google.com",           // single_uri
    223       NULL, NULL, NULL, NULL,     // per-proto
    224       ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8",  // bypass_rules
    225     },
    226 
    227     // Expected result.
    228     false,                          // auto_detect
    229     GURL(),                         // pac_url
    230     net::ProxyRulesExpectation::Single(                      // proxy_rules
    231         "www.google.com:80",                                 // single proxy
    232         "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),  // bypass_rules
    233   },
    234 };  // tests
    235 
    236 }  // namespace
    237 
    238 class ProxyConfigServiceImplTest : public PlatformTest {
    239  protected:
    240   ProxyConfigServiceImplTest()
    241       : ui_thread_(BrowserThread::UI, &message_loop_),
    242         io_thread_(BrowserThread::IO, &message_loop_) {
    243   }
    244 
    245   virtual ~ProxyConfigServiceImplTest() {
    246     config_service_ = NULL;
    247     MessageLoop::current()->RunAllPending();
    248   }
    249 
    250   void CreateConfigService(
    251       const ProxyConfigServiceImpl::ProxyConfig& init_config) {
    252     // Instantiate proxy config service with |init_config|.
    253     config_service_ = new ProxyConfigServiceImpl(init_config);
    254   }
    255 
    256   void SetAutomaticProxy(
    257       ProxyConfigServiceImpl::ProxyConfig::Mode mode,
    258       ProxyConfigServiceImpl::ProxyConfig::Source source,
    259       const char* pac_url,
    260       ProxyConfigServiceImpl::ProxyConfig* config,
    261       ProxyConfigServiceImpl::ProxyConfig::AutomaticProxy* automatic_proxy) {
    262     config->mode = mode;
    263     automatic_proxy->source = source;
    264     if (pac_url)
    265       automatic_proxy->pac_url = GURL(pac_url);
    266   }
    267 
    268   void SetManualProxy(
    269       ProxyConfigServiceImpl::ProxyConfig::Mode mode,
    270       ProxyConfigServiceImpl::ProxyConfig::Source source,
    271       const char* server_uri,
    272       net::ProxyServer::Scheme scheme,
    273       ProxyConfigServiceImpl::ProxyConfig* config,
    274       ProxyConfigServiceImpl::ProxyConfig::ManualProxy* manual_proxy) {
    275     if (!server_uri)
    276       return;
    277     config->mode = mode;
    278     manual_proxy->source = source;
    279     manual_proxy->server = net::ProxyServer::FromURI(server_uri, scheme);
    280   }
    281 
    282   void InitConfigWithTestInput(
    283       const Input& input, ProxyConfigServiceImpl::ProxyConfig::Source source,
    284       ProxyConfigServiceImpl::ProxyConfig* init_config) {
    285     switch (input.mode) {
    286       case MK_MODE(DIRECT):
    287       case MK_MODE(AUTO_DETECT):
    288       case MK_MODE(PAC_SCRIPT):
    289         SetAutomaticProxy(input.mode, source, input.pac_url, init_config,
    290                           &init_config->automatic_proxy);
    291         return;
    292       case MK_MODE(SINGLE_PROXY):
    293         SetManualProxy(input.mode, source, input.single_uri, MK_SCHM(HTTP),
    294                        init_config, &init_config->single_proxy);
    295         break;
    296       case MK_MODE(PROXY_PER_SCHEME):
    297         SetManualProxy(input.mode, source, input.http_uri, MK_SCHM(HTTP),
    298                        init_config, &init_config->http_proxy);
    299         SetManualProxy(input.mode, source, input.https_uri, MK_SCHM(HTTPS),
    300                        init_config, &init_config->https_proxy);
    301         SetManualProxy(input.mode, source, input.ftp_uri, MK_SCHM(HTTP),
    302                        init_config, &init_config->ftp_proxy);
    303         SetManualProxy(input.mode, source, input.socks_uri, MK_SCHM(SOCKS5),
    304                        init_config, &init_config->socks_proxy);
    305         break;
    306     }
    307     if (input.bypass_rules) {
    308       init_config->bypass_rules.ParseFromStringUsingSuffixMatching(
    309           input.bypass_rules);
    310     }
    311   }
    312 
    313   void TestReadWriteAccessForMode(const Input& input,
    314       ProxyConfigServiceImpl::ProxyConfig::Source source) {
    315     // Init config from |source|.
    316     ProxyConfigServiceImpl::ProxyConfig init_config;
    317     InitConfigWithTestInput(input, source, &init_config);
    318     CreateConfigService(init_config);
    319 
    320     ProxyConfigServiceImpl::ProxyConfig config;
    321     config_service()->UIGetProxyConfig(&config);
    322 
    323     // For owner, write access to config should be equal CanBeWrittenByOwner().
    324     // For non-owner, config is never writeable.
    325     bool expected_writeable_by_owner = CanBeWrittenByOwner(source);
    326     if (config.mode == MK_MODE(PROXY_PER_SCHEME)) {
    327       if (input.http_uri) {
    328         EXPECT_EQ(expected_writeable_by_owner,
    329                   config.CanBeWrittenByUser(true, "http"));
    330         EXPECT_FALSE(config.CanBeWrittenByUser(false, "http"));
    331       }
    332       if (input.https_uri) {
    333         EXPECT_EQ(expected_writeable_by_owner,
    334                   config.CanBeWrittenByUser(true, "http"));
    335         EXPECT_FALSE(config.CanBeWrittenByUser(false, "https"));
    336       }
    337       if (input.ftp_uri) {
    338         EXPECT_EQ(expected_writeable_by_owner,
    339                   config.CanBeWrittenByUser(true, "http"));
    340         EXPECT_FALSE(config.CanBeWrittenByUser(false, "ftp"));
    341       }
    342       if (input.socks_uri) {
    343         EXPECT_EQ(expected_writeable_by_owner,
    344                   config.CanBeWrittenByUser(true, "http"));
    345         EXPECT_FALSE(config.CanBeWrittenByUser(false, "socks"));
    346       }
    347     } else {
    348       EXPECT_EQ(expected_writeable_by_owner,
    349                 config.CanBeWrittenByUser(true, std::string()));
    350       EXPECT_FALSE(config.CanBeWrittenByUser(false, std::string()));
    351     }
    352   }
    353 
    354   void TestReadWriteAccessForScheme(
    355       ProxyConfigServiceImpl::ProxyConfig::Source source,
    356       const char* server_uri,
    357       const std::string& scheme) {
    358     // Init with manual |scheme| proxy.
    359     ProxyConfigServiceImpl::ProxyConfig init_config;
    360     ProxyConfigServiceImpl::ProxyConfig::ManualProxy* proxy =
    361         init_config.MapSchemeToProxy(scheme);
    362     net::ProxyServer::Scheme net_scheme = MK_SCHM(HTTP);
    363     if (scheme == "http" || scheme == "ftp")
    364       net_scheme = MK_SCHM(HTTP);
    365     else if (scheme == "https")
    366       net_scheme = MK_SCHM(HTTPS);
    367     else if (scheme == "socks")
    368       net_scheme = MK_SCHM(SOCKS4);
    369     SetManualProxy(MK_MODE(PROXY_PER_SCHEME), source, server_uri, net_scheme,
    370                    &init_config, proxy);
    371     CreateConfigService(init_config);
    372 
    373     ProxyConfigServiceImpl::ProxyConfig config;
    374     config_service()->UIGetProxyConfig(&config);
    375 
    376     // For owner, write access to config should be equal CanBeWrittenByOwner().
    377     // For non-owner, config is never writeable.
    378     bool expected_writeable_by_owner = CanBeWrittenByOwner(source);
    379     EXPECT_EQ(expected_writeable_by_owner,
    380               config.CanBeWrittenByUser(true, scheme));
    381     EXPECT_FALSE(config.CanBeWrittenByUser(false, scheme));
    382 
    383     const char* all_schemes[] = {
    384       "http", "https", "ftp", "socks",
    385     };
    386 
    387     // Rest of protos should be writeable by owner, but not writeable by
    388     // non-owner.
    389     for (size_t i = 0; i < ARRAYSIZE_UNSAFE(all_schemes); ++i) {
    390       if (scheme == all_schemes[i])
    391         continue;
    392       EXPECT_TRUE(config.CanBeWrittenByUser(true, all_schemes[i]));
    393       EXPECT_FALSE(config.CanBeWrittenByUser(false, all_schemes[i]));
    394     }
    395   }
    396 
    397   // Synchronously gets the latest proxy config.
    398   bool SyncGetLatestProxyConfig(net::ProxyConfig* config) {
    399     // Let message loop process all messages.
    400     MessageLoop::current()->RunAllPending();
    401     // Calls IOGetProxyConfig (which is called from
    402     // ProxyConfigService::GetLatestProxyConfig), running on faked IO thread.
    403     return config_service_->IOGetProxyConfig(config);
    404   }
    405 
    406   ProxyConfigServiceImpl* config_service() const {
    407     return config_service_;
    408   }
    409 
    410  private:
    411   bool CanBeWrittenByOwner(
    412     ProxyConfigServiceImpl::ProxyConfig::Source source) const {
    413     return source == MK_SRC(POLICY) ? false : true;
    414   }
    415 
    416   ScopedStubCrosEnabler stub_cros_enabler_;
    417   MessageLoop message_loop_;
    418   BrowserThread ui_thread_;
    419   BrowserThread io_thread_;
    420 
    421   scoped_refptr<ProxyConfigServiceImpl> config_service_;
    422 };
    423 
    424 TEST_F(ProxyConfigServiceImplTest, ChromeosProxyConfigToNetProxyConfig) {
    425   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    426     SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
    427                               tests[i].description.c_str()));
    428 
    429     ProxyConfigServiceImpl::ProxyConfig init_config;
    430     InitConfigWithTestInput(tests[i].input, MK_SRC(OWNER), &init_config);
    431     CreateConfigService(init_config);
    432 
    433     net::ProxyConfig config;
    434     SyncGetLatestProxyConfig(&config);
    435 
    436     EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
    437     EXPECT_EQ(tests[i].pac_url, config.pac_url());
    438     EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules()));
    439   }
    440 }
    441 
    442 TEST_F(ProxyConfigServiceImplTest, ModifyFromUI) {
    443   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    444     SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
    445                               tests[i].description.c_str()));
    446 
    447     // Init with direct.
    448     ProxyConfigServiceImpl::ProxyConfig init_config;
    449     SetAutomaticProxy(MK_MODE(DIRECT), MK_SRC(OWNER), NULL, &init_config,
    450                       &init_config.automatic_proxy);
    451     CreateConfigService(init_config);
    452 
    453     // Set config to tests[i].input via UI.
    454     net::ProxyBypassRules bypass_rules;
    455     const Input& input = tests[i].input;
    456     switch (input.mode) {
    457       case MK_MODE(DIRECT) :
    458         config_service()->UISetProxyConfigToDirect();
    459         break;
    460       case MK_MODE(AUTO_DETECT) :
    461         config_service()->UISetProxyConfigToAutoDetect();
    462         break;
    463       case MK_MODE(PAC_SCRIPT) :
    464         config_service()->UISetProxyConfigToPACScript(GURL(input.pac_url));
    465         break;
    466       case MK_MODE(SINGLE_PROXY) :
    467         config_service()->UISetProxyConfigToSingleProxy(
    468             net::ProxyServer::FromURI(input.single_uri, MK_SCHM(HTTP)));
    469         if (input.bypass_rules) {
    470           bypass_rules.ParseFromStringUsingSuffixMatching(input.bypass_rules);
    471           config_service()->UISetProxyConfigBypassRules(bypass_rules);
    472         }
    473         break;
    474       case MK_MODE(PROXY_PER_SCHEME) :
    475         if (input.http_uri) {
    476           config_service()->UISetProxyConfigToProxyPerScheme("http",
    477                   net::ProxyServer::FromURI(input.http_uri, MK_SCHM(HTTP)));
    478         }
    479         if (input.https_uri) {
    480           config_service()->UISetProxyConfigToProxyPerScheme("https",
    481               net::ProxyServer::FromURI(input.https_uri, MK_SCHM(HTTPS)));
    482         }
    483         if (input.ftp_uri) {
    484           config_service()->UISetProxyConfigToProxyPerScheme("ftp",
    485               net::ProxyServer::FromURI(input.ftp_uri, MK_SCHM(HTTP)));
    486         }
    487         if (input.socks_uri) {
    488           config_service()->UISetProxyConfigToProxyPerScheme("socks",
    489               net::ProxyServer::FromURI(input.socks_uri, MK_SCHM(SOCKS5)));
    490         }
    491         if (input.bypass_rules) {
    492           bypass_rules.ParseFromStringUsingSuffixMatching(input.bypass_rules);
    493           config_service()->UISetProxyConfigBypassRules(bypass_rules);
    494         }
    495         break;
    496     }
    497 
    498     // Retrieve config from IO thread.
    499     net::ProxyConfig io_config;
    500     SyncGetLatestProxyConfig(&io_config);
    501     EXPECT_EQ(tests[i].auto_detect, io_config.auto_detect());
    502     EXPECT_EQ(tests[i].pac_url, io_config.pac_url());
    503     EXPECT_TRUE(tests[i].proxy_rules.Matches(io_config.proxy_rules()));
    504 
    505     // Retrieve config from UI thread.
    506     ProxyConfigServiceImpl::ProxyConfig ui_config;
    507     config_service()->UIGetProxyConfig(&ui_config);
    508     EXPECT_EQ(input.mode, ui_config.mode);
    509     if (tests[i].is_valid) {
    510       if (input.pac_url)
    511         EXPECT_EQ(GURL(input.pac_url), ui_config.automatic_proxy.pac_url);
    512       const net::ProxyRulesExpectation& proxy_rules = tests[i].proxy_rules;
    513       if (input.single_uri)
    514         EXPECT_EQ(proxy_rules.single_proxy,
    515                   ui_config.single_proxy.server.ToURI());
    516       if (input.http_uri)
    517         EXPECT_EQ(proxy_rules.proxy_for_http,
    518                   ui_config.http_proxy.server.ToURI());
    519       if (input.https_uri)
    520         EXPECT_EQ(proxy_rules.proxy_for_https,
    521                   ui_config.https_proxy.server.ToURI());
    522       if (input.ftp_uri)
    523         EXPECT_EQ(proxy_rules.proxy_for_ftp,
    524                   ui_config.ftp_proxy.server.ToURI());
    525       if (input.socks_uri) {
    526         EXPECT_EQ(proxy_rules.fallback_proxy,
    527                   ui_config.socks_proxy.server.ToURI());
    528       }
    529       if (input.bypass_rules)
    530         EXPECT_TRUE(bypass_rules.Equals(ui_config.bypass_rules));
    531     }
    532   }
    533 }
    534 
    535 TEST_F(ProxyConfigServiceImplTest, ProxyChangedObserver) {
    536   // This is used to observe for OnProxyConfigChanged notification.
    537   class ProxyChangedObserver : public net::ProxyConfigService::Observer {
    538    public:
    539     explicit ProxyChangedObserver(
    540         const scoped_refptr<ProxyConfigServiceImpl>& config_service)
    541         : config_service_(config_service) {
    542       config_service_->AddObserver(this);
    543     }
    544     virtual ~ProxyChangedObserver() {
    545       config_service_->RemoveObserver(this);
    546     }
    547     net::ProxyConfigService::ConfigAvailability availability() const {
    548       return availability_;
    549     }
    550     const net::ProxyConfig& config() const {
    551       return config_;
    552     }
    553 
    554    private:
    555     virtual void OnProxyConfigChanged(
    556         const net::ProxyConfig& config,
    557         net::ProxyConfigService::ConfigAvailability availability) {
    558       config_ = config;
    559       availability_ = availability;
    560     }
    561 
    562     scoped_refptr<ProxyConfigServiceImpl> config_service_;
    563     net::ProxyConfigService::ConfigAvailability availability_;
    564     net::ProxyConfig config_;
    565   };
    566 
    567   // Init with direct.
    568   ProxyConfigServiceImpl::ProxyConfig init_config;
    569   SetAutomaticProxy(MK_MODE(DIRECT), MK_SRC(OWNER), NULL, &init_config,
    570                     &init_config.automatic_proxy);
    571   CreateConfigService(init_config);
    572 
    573   ProxyChangedObserver observer(config_service());
    574 
    575   // Set to pac script from UI.
    576   EXPECT_TRUE(config_service()->UISetProxyConfigToPACScript(
    577       GURL("http://wpad.dat")));
    578   // Retrieve config from IO thread.
    579   net::ProxyConfig io_config;
    580   SyncGetLatestProxyConfig(&io_config);
    581 
    582   // Observer should have gotten the same new proxy config.
    583   EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, observer.availability());
    584   EXPECT_TRUE(io_config.Equals(observer.config()));
    585 }
    586 
    587 TEST_F(ProxyConfigServiceImplTest, SerializeAndDeserialize) {
    588   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    589     if (!tests[i].is_valid)
    590       continue;
    591 
    592     SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
    593                               tests[i].description.c_str()));
    594 
    595     ProxyConfigServiceImpl::ProxyConfig source_config;
    596     InitConfigWithTestInput(tests[i].input, MK_SRC(OWNER), &source_config);
    597 
    598     // Serialize source_config into std::string.
    599     std::string serialized_value;
    600     EXPECT_TRUE(source_config.Serialize(&serialized_value));
    601 
    602     // Deserialize std:string into target_config.
    603     ProxyConfigServiceImpl::ProxyConfig target_config;
    604     EXPECT_TRUE(target_config.Deserialize(serialized_value));
    605 
    606     // Compare the configs after serialization and deserialization.
    607     net::ProxyConfig net_src_cfg;
    608     net::ProxyConfig net_tgt_cfg;
    609     source_config.ToNetProxyConfig(&net_src_cfg);
    610     target_config.ToNetProxyConfig(&net_tgt_cfg);
    611 #if !defined(NDEBUG)
    612     if (!net_src_cfg.Equals(net_tgt_cfg)) {
    613       std::string src_output, tgt_output;
    614       JSONStringValueSerializer src_serializer(&src_output);
    615       src_serializer.Serialize(*net_src_cfg.ToValue());
    616       JSONStringValueSerializer tgt_serializer(&tgt_output);
    617       tgt_serializer.Serialize(*net_tgt_cfg.ToValue());
    618       VLOG(1) << "source:\n" << src_output
    619               << "\ntarget:\n" << tgt_output;
    620     }
    621 #endif  // !defined(NDEBUG)
    622     EXPECT_TRUE(net_src_cfg.Equals(net_tgt_cfg));
    623   }
    624 }
    625 
    626 TEST_F(ProxyConfigServiceImplTest, ReadWriteAccessForPolicySource) {
    627   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    628     if (!tests[i].test_read_write_access)
    629       continue;
    630     SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
    631                               tests[i].description.c_str()));
    632     TestReadWriteAccessForMode(tests[i].input, MK_SRC(POLICY));
    633   }
    634 }
    635 
    636 TEST_F(ProxyConfigServiceImplTest, ReadWriteAccessForOwnerSource) {
    637   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    638     if (!tests[i].test_read_write_access)
    639       continue;
    640     SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
    641                               tests[i].description.c_str()));
    642     TestReadWriteAccessForMode(tests[i].input, MK_SRC(OWNER));
    643   }
    644 }
    645 
    646 TEST_F(ProxyConfigServiceImplTest, ReadWriteAccessForMixedSchemes) {
    647   const char* http_uri = "www.google.com:80";
    648   const char* https_uri = "www.foo.com:110";
    649   const char* ftp_uri = "ftp.foo.com:121";
    650   const char* socks_uri = "socks.com:888";
    651 
    652   // Init with policy source.
    653   TestReadWriteAccessForScheme(MK_SRC(POLICY), http_uri, "http");
    654   TestReadWriteAccessForScheme(MK_SRC(POLICY), https_uri, "https");
    655   TestReadWriteAccessForScheme(MK_SRC(POLICY), ftp_uri, "ftp");
    656   TestReadWriteAccessForScheme(MK_SRC(POLICY), socks_uri, "socks");
    657 
    658   // Init with owner source.
    659   TestReadWriteAccessForScheme(MK_SRC(OWNER), http_uri, "http");
    660   TestReadWriteAccessForScheme(MK_SRC(OWNER), https_uri, "https");
    661   TestReadWriteAccessForScheme(MK_SRC(OWNER), ftp_uri, "ftp");
    662   TestReadWriteAccessForScheme(MK_SRC(OWNER), socks_uri, "socks");
    663 }
    664 
    665 }  // namespace chromeos
    666