13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/basictypes.h"
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/bind.h"
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/callback.h"
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/command_line.h"
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/compiler_specific.h"
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/message_loop/message_loop.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/local_discovery/test_service_discovery_client.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/profiles/profile.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/common/url_constants.h"
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/test/base/ui_test_utils.h"
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/test/base/web_ui_browser_test.h"
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
23e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_manager.h"
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/signin_manager_base.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/http/http_status_code.h"
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/test_url_fetcher_factory.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "net/url_request/url_request_status.h"
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request_test_util.h"
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_CHROMEOS)
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/prefs/pref_service.h"
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/common/pref_names.h"
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::InvokeWithoutArgs;
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::Return;
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::AtLeast;
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::DoDefault;
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::DoAll;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::InSequence;
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::StrictMock;
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::AnyNumber;
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::InvokeWithoutArgs;
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::Return;
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using testing::AtLeast;
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace local_discovery {
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace {
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const uint8 kQueryData[] = {
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Header
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // Flags not set.
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,               // Set QDCOUNT (question count) to 1, all the
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // rest are 0 for a query.
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Question
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x04, '_', 't', 'c', 'p',
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x0c,               // QTYPE: A query.
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,               // QCLASS: IN class. Unicast bit not set.
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const uint8 kAnnouncePacket[] = {
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Header
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // ID is zeroed out
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x80, 0x00,               // Standard query response, no error
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // No questions (for simplicity)
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x05,               // 5 RR (answers)
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // 0 authority RRs
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // 0 additional RRs
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x04, '_', 't', 'c', 'p',
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x0c,        // TYPE is PTR.
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN.
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 32768 second.
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x10, 0x00,
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x0c,        // RDLENGTH is 12 bytes.
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0xc0, 0x0c,
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0xc0, 0x0c,
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x10,        // TYPE is TXT.
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN.
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 32768 seconds.
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x00,
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  0x00, 0x41,        // RDLENGTH is 69 bytes.
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x03, 'i', 'd', '=',
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x10, 't', 'y', '=', 'S', 'a', 'm', 'p', 'l', 'e', ' ',
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'd', 'e', 'v', 'i', 'c', 'e',
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x1e, 'n', 'o', 't', 'e', '=',
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'S', 'a', 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', ' ',
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n',
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  0x0c, 't', 'y', 'p', 'e', '=', 'p', 'r', 'i', 'n', 't', 'e', 'r',
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0xc0, 0x0c,
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x21,        // Type is SRV
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 32768 second.
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x10, 0x00,
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x17,        // RDLENGTH is 23
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x22, 0xb8,        // port 8888
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // Type is A
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 32768 second.
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x10, 0x00,
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x04,        // RDLENGTH is 4
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x02, 0x03, 0x04,  // 1.2.3.4
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x1C,        // Type is AAAA
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 32768 second.
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x10, 0x00,
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x10,        // RDLENGTH is 16
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x02, 0x03, 0x04,  // 1.2.3.4
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x02, 0x03, 0x04,
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x02, 0x03, 0x04,
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x02, 0x03, 0x04,
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const uint8 kGoodbyePacket[] = {
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Header
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // ID is zeroed out
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x80, 0x00,               // Standard query response, RA, no error
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // No questions (for simplicity)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x02,               // 1 RR (answers)
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // 0 authority RRs
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // 0 additional RRs
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x04, '_', 't', 'c', 'p',
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x0c,        // TYPE is PTR.
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN.
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 0 seconds.
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x0c,        // RDLENGTH is 12 bytes.
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0xc0, 0x0c,
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0xc0, 0x0c,
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x21,        // Type is SRV
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x01,        // CLASS is IN
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 0 seconds.
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x00,
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x17,        // RDLENGTH is 23
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x00,
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00, 0x00,
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x22, 0xb8,        // port 8888
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  0x00,
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const uint8 kAnnouncePacketRegistered[] = {
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Header
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // ID is zeroed out
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x80, 0x00,               // Standard query response, RA, no error
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // No questions (for simplicity)
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,               // 1 RR (answers)
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // 0 authority RRs
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,               // 0 additional RRs
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x04, '_', 't', 'c', 'p',
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x05, 'l', 'o', 'c', 'a', 'l',
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00,
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x10,        // TYPE is TXT.
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x01,        // CLASS is IN.
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x00,        // TTL (4 bytes) is 32768 seconds.
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x01, 0x00,
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x00, 0x3b,        // RDLENGTH is 76 bytes.
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x0a, 'i', 'd', '=', 's', 'o', 'm', 'e', '_', 'i', 'd',
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x10, 't', 'y', '=', 'S', 'a', 'm', 'p', 'l', 'e', ' ',
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'd', 'e', 'v', 'i', 'c', 'e',
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  0x1e, 'n', 'o', 't', 'e', '=',
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'S', 'a', 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', ' ',
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n',
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseInfo[] = "{"
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "     \"x-privet-token\" : \"MyPrivetToken\""
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "}";
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const char kResponseInfoWithID[] = "{"
2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "     \"x-privet-token\" : \"MyPrivetToken\","
2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "     \"id\" : \"my_id\""
2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "}";
2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseRegisterStart[] = "{"
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "     \"action\": \"start\","
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "     \"user\": \"user@host.com\""
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "}";
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseRegisterClaimTokenNoConfirm[] = "{"
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"action\": \"getClaimToken\","
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"user\": \"user@host.com\","
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"error\": \"pending_user_action\","
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"timeout\": 1"
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "}";
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseRegisterClaimTokenConfirm[] = "{"
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"action\": \"getClaimToken\","
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"user\": \"user@host.com\","
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"token\": \"MySampleToken\","
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"claim_url\": \"http://someurl.com/\""
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "}";
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseCloudPrintConfirm[] = "{ \"success\": true }";
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseRegisterComplete[] = "{"
2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"action\": \"complete\","
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"user\": \"user@host.com\","
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "    \"device_id\": \"my_id\""
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "}";
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kResponseGaiaToken[] = "{"
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "  \"access_token\": \"at1\","
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "  \"expires_in\": 3600,"
2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "  \"token_type\": \"Bearer\""
2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "}";
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kResponseGaiaId[] = "{"
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  \"id\": \"12345\""
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "}";
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kURLInfo[] = "http://1.2.3.4:8888/privet/info";
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kURLRegisterStart[] =
2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "http://1.2.3.4:8888/privet/register?action=start&user=user%40host.com";
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kURLRegisterClaimToken[] =
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "http://1.2.3.4:8888/privet/register?action=getClaimToken&"
2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "user=user%40host.com";
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kURLCloudPrintConfirm[] =
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "https://www.google.com/cloudprint/confirm?token=MySampleToken";
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kURLRegisterComplete[] =
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "http://1.2.3.4:8888/privet/register?action=complete&user=user%40host.com";
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kURLGaiaToken[] =
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "https://accounts.google.com/o/oauth2/token";
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kSampleUser[] = "user@host.com";
2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)class TestMessageLoopCondition {
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TestMessageLoopCondition() : signaled_(false),
2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               waiting_(false) {
2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ~TestMessageLoopCondition() {
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Signal a waiting method that it can continue executing.
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void Signal() {
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    signaled_ = true;
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (waiting_)
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::MessageLoop::current()->Quit();
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Pause execution and recursively run the message loop until |Signal()| is
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // called. Do not pause if |Signal()| has already been called.
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void Wait() {
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    while (!signaled_) {
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      waiting_ = true;
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::MessageLoop::current()->Run();
3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      waiting_ = false;
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    signaled_ = false;
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private:
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool signaled_;
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool waiting_;
3083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestMessageLoopCondition);
3103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class MockableFakeURLFetcherCreator {
3133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  MockableFakeURLFetcherCreator() {
3153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ~MockableFakeURLFetcherCreator() {
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  MOCK_METHOD1(OnCreateFakeURLFetcher, void(const std::string& url));
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<net::FakeURLFetcher> CreateFakeURLFetcher(
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const GURL& url,
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      net::URLFetcherDelegate* delegate,
3250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      const std::string& response_data,
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      net::HttpStatusCode response_code,
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      net::URLRequestStatus::Status status) {
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    OnCreateFakeURLFetcher(url.spec());
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return scoped_ptr<net::FakeURLFetcher>(new net::FakeURLFetcher(
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        url, delegate, response_data, response_code, status));
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  net::FakeURLFetcherFactory::FakeURLFetcherCreator callback() {
3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return base::Bind(&MockableFakeURLFetcherCreator::CreateFakeURLFetcher,
3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                      base::Unretained(this));
3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
3383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)class LocalDiscoveryUITest : public WebUIBrowserTest {
3403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  LocalDiscoveryUITest() : fake_fetcher_factory_(
3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      &fetcher_impl_factory_,
3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      fake_url_fetcher_creator_.callback()) {
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual ~LocalDiscoveryUITest() {
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual void SetUpOnMainThread() OVERRIDE {
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    WebUIBrowserTest::SetUpOnMainThread();
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    test_service_discovery_client_ = new TestServiceDiscoveryClient();
3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    test_service_discovery_client_->Start();
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    EXPECT_CALL(
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        *test_service_discovery_client_.get(),
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        OnSendTo(std::string((const char*)kQueryData, sizeof(kQueryData))))
3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .Times(AtLeast(2))
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .WillOnce(InvokeWithoutArgs(&condition_devices_listed_,
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    &TestMessageLoopCondition::Signal))
3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .WillRepeatedly(Return());
3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SigninManagerBase* signin_manager =
3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SigninManagerFactory::GetForProfile(browser()->profile());
3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_CHROMEOS)
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Chrome OS initializes prefs::kGoogleServicesUsername to "stub user" so
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // we need to override it as well.
367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    browser()->profile()->GetPrefs()->
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        SetString(prefs::kGoogleServicesUsername, kSampleUser);
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(signin_manager);
3714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    signin_manager->SetAuthenticatedUsername(kSampleUser);
3724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
3744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        GURL(kURLInfo),
3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kResponseInfo,
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::HTTP_OK,
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::URLRequestStatus::SUCCESS);
3784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        GURL(kURLRegisterStart),
3814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kResponseRegisterStart,
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::HTTP_OK,
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::URLRequestStatus::SUCCESS);
3844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
3864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        GURL(kURLRegisterClaimToken),
3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kResponseRegisterClaimTokenNoConfirm,
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::HTTP_OK,
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::URLRequestStatus::SUCCESS);
3904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        GURL(kURLCloudPrintConfirm),
3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kResponseCloudPrintConfirm,
394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::HTTP_OK,
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::URLRequestStatus::SUCCESS);
3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        GURL(kURLRegisterComplete),
3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kResponseRegisterComplete,
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::HTTP_OK,
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::URLRequestStatus::SUCCESS);
4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        GURL(kURLGaiaToken),
4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kResponseGaiaToken,
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::HTTP_OK,
407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        net::URLRequestStatus::SUCCESS);
4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kURLGaiaToken))
4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .Times(AnyNumber());
4124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fake_fetcher_factory().SetFakeResponse(
414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        GaiaUrls::GetInstance()->oauth_user_info_url(),
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kResponseGaiaId,
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        net::HTTP_OK,
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        net::URLRequestStatus::SUCCESS);
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        GaiaUrls::GetInstance()->oauth_user_info_url().spec()))
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .Times(AnyNumber());
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ProfileOAuth2TokenService* token_service =
4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile());
4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    token_service->UpdateCredentials("user@host.com", "MyFakeToken");
4273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    AddLibrary(base::FilePath(FILE_PATH_LITERAL("local_discovery_ui_test.js")));
4293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
4323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    WebUIBrowserTest::SetUpCommandLine(command_line);
4333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void RunFor(base::TimeDelta time_period) {
4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::CancelableCallback<void()> callback(base::Bind(
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        &base::MessageLoop::Quit, base::Unretained(
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            base::MessageLoop::current())));
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE, callback.callback(), time_period);
4414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::MessageLoop::current()->Run();
4434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    callback.Cancel();
4444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TestServiceDiscoveryClient* test_service_discovery_client() {
4474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return test_service_discovery_client_.get();
4484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TestMessageLoopCondition& condition_devices_listed() {
4513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return condition_devices_listed_;
4523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  net::FakeURLFetcherFactory& fake_fetcher_factory() {
4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return fake_fetcher_factory_;
4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  MockableFakeURLFetcherCreator& fake_url_fetcher_creator() {
4594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return fake_url_fetcher_creator_;
4604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private:
4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_refptr<TestServiceDiscoveryClient> test_service_discovery_client_;
4643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TestMessageLoopCondition condition_devices_listed_;
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  net::URLFetcherImplFactory fetcher_impl_factory_;
4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  StrictMock<MockableFakeURLFetcherCreator> fake_url_fetcher_creator_;
4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  net::FakeURLFetcherFactory fake_fetcher_factory_;
4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(LocalDiscoveryUITest);
4713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
4723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, EmptyTest) {
47458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ui_test_utils::NavigateToURL(browser(), GURL(
475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      chrome::kChromeUIDevicesURL));
4763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  condition_devices_listed().Wait();
477424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices"));
4783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, AddRowTest) {
48158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ui_test_utils::NavigateToURL(browser(), GURL(
482d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      chrome::kChromeUIDevicesURL));
4833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  condition_devices_listed().Wait();
4843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  test_service_discovery_client()->SimulateReceive(
4864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kAnnouncePacket, sizeof(kAnnouncePacket));
4873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
4893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
490424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice"));
4913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  test_service_discovery_client()->SimulateReceive(
4934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kGoodbyePacket, sizeof(kGoodbyePacket));
4944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RunFor(base::TimeDelta::FromMilliseconds(1100));
4963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
497424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices"));
4983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, RegisterTest) {
5024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TestMessageLoopCondition condition_token_claimed;
5034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ui_test_utils::NavigateToURL(browser(), GURL(
5054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      chrome::kChromeUIDevicesURL));
5064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  condition_devices_listed().Wait();
5074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  test_service_discovery_client()->SimulateReceive(
5094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kAnnouncePacket, sizeof(kAnnouncePacket));
5104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
5124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice"));
5144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("registerShowOverlay"));
5164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  {
5184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    InSequence s;
5194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo));
5204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
5214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kURLRegisterStart));
5224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
5234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kURLRegisterClaimToken))
5244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .WillOnce(InvokeWithoutArgs(&condition_token_claimed,
5254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    &TestMessageLoopCondition::Signal));
5264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("registerBegin"));
5294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  condition_token_claimed.Wait();
5314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("expectPageAdding1"));
5334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  fake_fetcher_factory().SetFakeResponse(
5354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GURL(kURLRegisterClaimToken),
5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kResponseRegisterClaimTokenConfirm,
537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      net::HTTP_OK,
538f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      net::URLRequestStatus::SUCCESS);
5394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  fake_fetcher_factory().SetFakeResponse(
5411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      GURL(kURLInfo),
5421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      kResponseInfoWithID,
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      net::HTTP_OK,
544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      net::URLRequestStatus::SUCCESS);
5451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
5464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  {
5474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    InSequence s;
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kURLRegisterClaimToken));
5504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
5514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kURLCloudPrintConfirm));
5524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
5531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        kURLRegisterComplete));
5541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo))
5554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        .WillOnce(InvokeWithoutArgs(&condition_token_claimed,
5564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    &TestMessageLoopCondition::Signal));
5574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  condition_token_claimed.Wait();
5604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  test_service_discovery_client()->SimulateReceive(
5624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kAnnouncePacketRegistered, sizeof(kAnnouncePacketRegistered));
5634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
5654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("expectRegisterDone"));
5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace
5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace local_discovery
572