Coverage for /Syzygy/kasko/service_bridge_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1181180.C++test

Line-by-line coverage:

   1    :  // Copyright 2014 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/kasko/service_bridge.h"
  16    :  
  17    :  #include <Windows.h>  // NOLINT
  18    :  #include <Rpc.h>
  19    :  
  20    :  #include <vector>
  21    :  
  22    :  #include "base/bind.h"
  23    :  #include "base/callback.h"
  24    :  #include "base/callback_helpers.h"
  25    :  #include "base/location.h"
  26    :  #include "base/macros.h"
  27    :  #include "base/message_loop/message_loop.h"
  28    :  #include "base/process/process_handle.h"
  29    :  #include "base/strings/string16.h"
  30    :  #include "base/strings/string_number_conversions.h"
  31    :  #include "base/synchronization/waitable_event.h"
  32    :  #include "base/threading/thread.h"
  33    :  #include "gtest/gtest.h"
  34    :  #include "syzygy/common/rpc/helpers.h"
  35    :  #include "syzygy/kasko/kasko_rpc.h"
  36    :  #include "syzygy/kasko/service.h"
  37    :  #include "syzygy/kasko/testing/mock_service.h"
  38    :  
  39    :  namespace kasko {
  40    :  
  41    :  namespace {
  42    :  
  43    :  const base::char16* const kValidRpcProtocol = L"ncalrpc";
  44    :  const base::char16* const kTestRpcEndpointPrefix = L"syzygy-kasko-test-svc";
  45    :  
  46  E :  base::string16 GetTestEndpoint() {
  47  E :    return kTestRpcEndpointPrefix + base::UintToString16(::GetCurrentProcessId());
  48  E :  }
  49    :  
  50    :  class BlockingService : public Service {
  51    :   public:
  52    :    BlockingService(base::WaitableEvent* release_call,
  53    :                    base::WaitableEvent* blocking);
  54    :    virtual ~BlockingService();
  55    :  
  56    :    // Service implementation
  57    :    virtual void SendDiagnosticReport(
  58    :        base::ProcessId client_process_id,
  59    :        base::PlatformThreadId thread_id,
  60    :        const MinidumpRequest& request) override;
  61    :  
  62    :   private:
  63    :    base::WaitableEvent* release_call_;
  64    :    base::WaitableEvent* blocking_;
  65    :    DISALLOW_COPY_AND_ASSIGN(BlockingService);
  66    :  };
  67    :  
  68    :  BlockingService::BlockingService(base::WaitableEvent* release_call,
  69    :                                   base::WaitableEvent* blocking)
  70  E :      : release_call_(release_call), blocking_(blocking) {}
  71    :  
  72  E :  BlockingService::~BlockingService() {}
  73    :  
  74    :  void BlockingService::SendDiagnosticReport(
  75    :      base::ProcessId client_process_id,
  76    :      base::PlatformThreadId thread_id,
  77  E :      const MinidumpRequest& request) {
  78  E :    blocking_->Signal();
  79  E :    release_call_->Wait();
  80  E :  }
  81    :  
  82    :  void InvokeAndCheckRpcStatus(const base::Callback<RPC_STATUS(void)>& callback) {
  83    :    ASSERT_EQ(RPC_S_OK, callback.Run());
  84    :  }
  85    :  
  86    :  base::Closure WrapRpcStatusCallback(
  87    :      const base::Callback<RPC_STATUS(void)>& callback) {
  88    :    return base::Bind(InvokeAndCheckRpcStatus, callback);
  89    :  }
  90    :  
  91    :  void DoInvokeService(const base::string16& protocol,
  92    :                       const base::string16& endpoint,
  93    :                       bool* complete,
  94    :                       long exception_info_address,
  95    :                       long thread_id,
  96    :                       DumpType dump_type,
  97    :                       size_t memory_ranges_length,
  98    :                       const MemoryRange* memory_ranges,
  99    :                       size_t crash_keys_length,
 100    :                       const CrashKey* crash_keys,
 101    :                       size_t custom_streams_length,
 102  E :                       const CustomStream* custom_streams) {
 103  E :    common::rpc::ScopedRpcBinding rpc_binding;
 104  E :    ASSERT_TRUE(rpc_binding.Open(protocol, endpoint));
 105    :  
 106    :    ::MinidumpRequest rpc_request = {exception_info_address,
 107    :                                     thread_id,
 108    :                                     dump_type,
 109    :                                     memory_ranges_length,
 110    :                                     memory_ranges,
 111    :                                     crash_keys_length,
 112    :                                     crash_keys,
 113    :                                     custom_streams_length,
 114  E :                                     custom_streams};
 115    :  
 116    :    common::rpc::RpcStatus status = common::rpc::InvokeRpc(
 117  E :        KaskoClient_SendDiagnosticReport, rpc_binding.Get(), rpc_request);
 118  E :    ASSERT_FALSE(status.exception_occurred);
 119  E :    ASSERT_TRUE(status.succeeded());
 120  E :    *complete = true;
 121  E :  }
 122    :  
 123    :  }  // namespace
 124    :  
 125  E :  TEST(KaskoServiceBridgeTest, ConstructDestruct) {
 126  E :    std::vector<testing::MockService::CallRecord> call_log;
 127    :    {
 128    :      ServiceBridge instance(
 129    :          L"aaa", L"bbb",
 130  E :          scoped_ptr<Service>(new testing::MockService(&call_log)));
 131  E :    }
 132    :    {
 133    :      ServiceBridge instance(
 134    :          L"aaa", L"bbb",
 135  E :          scoped_ptr<Service>(new testing::MockService(&call_log)));
 136  E :    }
 137  E :  }
 138    :  
 139  E :  TEST(KaskoServiceBridgeTest, StopNonRunningInstance) {
 140  E :    std::vector<testing::MockService::CallRecord> call_log;
 141    :    ServiceBridge instance(
 142  E :        L"aaa", L"bbb", scoped_ptr<Service>(new testing::MockService(&call_log)));
 143  E :    instance.Stop();
 144  E :  }
 145    :  
 146  E :  TEST(KaskoServiceBridgeTest, FailToRunWithBadProtocol) {
 147  E :    std::vector<testing::MockService::CallRecord> call_log;
 148    :    {
 149    :      ServiceBridge instance(
 150    :          L"aaa", GetTestEndpoint(),
 151  E :          scoped_ptr<Service>(new testing::MockService(&call_log)));
 152  E :      ASSERT_FALSE(instance.Run());
 153    :      // Stop should not crash in this case.
 154  E :      instance.Stop();
 155  E :    }
 156  E :  }
 157    :  
 158  E :  TEST(KaskoServiceBridgeTest, RunSuccessfully) {
 159  E :    std::vector<testing::MockService::CallRecord> call_log;
 160    :  
 161    :    {
 162    :      ServiceBridge instance(
 163    :          kValidRpcProtocol, GetTestEndpoint(),
 164  E :          scoped_ptr<Service>(new testing::MockService(&call_log)));
 165  E :      ASSERT_TRUE(instance.Run());
 166  E :      instance.Stop();
 167    :  
 168    :      // Second run, same instance.
 169  E :      ASSERT_TRUE(instance.Run());
 170  E :      instance.Stop();
 171  E :    }
 172    :    {
 173    :      // Second instance.
 174    :      ServiceBridge instance(
 175    :          kValidRpcProtocol, GetTestEndpoint(),
 176  E :          scoped_ptr<Service>(new testing::MockService(&call_log)));
 177  E :      ASSERT_TRUE(instance.Run());
 178  E :      instance.Stop();
 179  E :    }
 180  E :  }
 181    :  
 182  E :  TEST(KaskoServiceBridgeTest, InvokeService) {
 183  E :    std::vector<testing::MockService::CallRecord> call_log;
 184    :  
 185  E :    base::string16 protocol = kValidRpcProtocol;
 186  E :    base::string16 endpoint = GetTestEndpoint();
 187    :    ServiceBridge instance(
 188    :        protocol, endpoint,
 189  E :        scoped_ptr<Service>(new testing::MockService(&call_log)));
 190  E :    ASSERT_TRUE(instance.Run());
 191    :  
 192    :    base::ScopedClosureRunner stop_service_bridge(
 193  E :        base::Bind(&ServiceBridge::Stop, base::Unretained(&instance)));
 194    :  
 195    :  
 196  E :    std::string stream_data = "hello world";
 197  E :    uint32_t kStreamType = 987;
 198    :    CustomStream custom_streams[] = {
 199    :        {kStreamType, stream_data.length(),
 200  E :         reinterpret_cast<const signed char*>(stream_data.data())}};
 201  E :    bool complete = false;
 202    :    CrashKey crash_keys[] = {{reinterpret_cast<const wchar_t*>(L"foo"),
 203    :                              reinterpret_cast<const wchar_t*>(L"bar")},
 204    :                             {reinterpret_cast<const wchar_t*>(L"hello"),
 205  E :                              reinterpret_cast<const wchar_t*>(L"world")}};
 206    :  
 207  E :    MemoryRange memory_ranges[] = {{0xdeadbeef, 123}};
 208    :  
 209    :    DoInvokeService(protocol, endpoint, &complete, 0, 0, SMALL_DUMP,
 210    :                    arraysize(memory_ranges), memory_ranges,
 211    :                    arraysize(crash_keys), crash_keys, arraysize(custom_streams),
 212  E :                    custom_streams);
 213  E :    ASSERT_TRUE(complete);
 214  E :    complete = false;
 215    :    DoInvokeService(protocol, endpoint, &complete, 1122, 3, LARGER_DUMP, 0,
 216  E :                    nullptr, 0, nullptr, 0, nullptr);
 217  E :    ASSERT_TRUE(complete);
 218    :  
 219  E :    ASSERT_EQ(2u, call_log.size());
 220    :  
 221    :    // First request
 222  E :    ASSERT_EQ(::GetCurrentProcessId(), call_log[0].client_process_id);
 223  E :    ASSERT_EQ(0, call_log[0].exception_info_address);
 224  E :    ASSERT_EQ(0, call_log[0].thread_id);
 225    :  
 226  E :    ASSERT_EQ(1u, call_log[0].user_selected_memory_ranges.size());
 227    :    ASSERT_EQ(memory_ranges[0].base_address,
 228  E :              call_log[0].user_selected_memory_ranges[0].start());
 229    :    ASSERT_EQ(memory_ranges[0].length,
 230  E :              call_log[0].user_selected_memory_ranges[0].size());
 231    :  
 232  E :    ASSERT_EQ(1u, call_log[0].custom_streams.size());
 233  E :    auto custom_streams_entry = call_log[0].custom_streams.find(kStreamType);
 234  E :    ASSERT_NE(call_log[0].custom_streams.end(), custom_streams_entry);
 235  E :    ASSERT_EQ(stream_data, custom_streams_entry->second);
 236    :  
 237  E :    ASSERT_EQ(2u, call_log[0].crash_keys.size());
 238  E :    auto crash_keys_entry = call_log[0].crash_keys.find(L"foo");
 239  E :    ASSERT_NE(call_log[0].crash_keys.end(), crash_keys_entry);
 240  E :    ASSERT_EQ(L"bar", crash_keys_entry->second);
 241  E :    crash_keys_entry = call_log[0].crash_keys.find(L"hello");
 242  E :    ASSERT_NE(call_log[0].crash_keys.end(), crash_keys_entry);
 243  E :    ASSERT_EQ(L"world", crash_keys_entry->second);
 244    :  
 245    :    // Second request
 246  E :    ASSERT_EQ(::GetCurrentProcessId(), call_log[1].client_process_id);
 247  E :    ASSERT_EQ(1122, call_log[1].exception_info_address);
 248  E :    ASSERT_EQ(3, call_log[1].thread_id);
 249  E :    ASSERT_EQ(0u, call_log[1].custom_streams.size());
 250  E :    ASSERT_EQ(0u, call_log[1].crash_keys.size());
 251  E :  }
 252    :  
 253    :  
 254  E :  TEST(KaskoServiceBridgeTest, StopBlocksUntilCallsComplete) {
 255  E :    base::WaitableEvent release_call(false, false);
 256  E :    base::WaitableEvent blocking(false, false);
 257    :  
 258  E :    base::string16 protocol = kValidRpcProtocol;
 259  E :    base::string16 endpoint = GetTestEndpoint();
 260    :    ServiceBridge instance(
 261    :        protocol, endpoint,
 262  E :        scoped_ptr<Service>(new BlockingService(&release_call, &blocking)));
 263  E :    ASSERT_TRUE(instance.Run());
 264    :  
 265    :    base::ScopedClosureRunner stop_service_bridge(
 266  E :        base::Bind(&ServiceBridge::Stop, base::Unretained(&instance)));
 267    :    // In case an assertion fails, make sure that we will not block.
 268    :    base::ScopedClosureRunner signal_release_call(base::Bind(
 269  E :        &base::WaitableEvent::Signal, base::Unretained(&release_call)));
 270    :  
 271  E :    bool complete = false;
 272    :    CrashKey crash_keys[] = {{reinterpret_cast<const wchar_t*>(L"foo"),
 273    :                              reinterpret_cast<const wchar_t*>(L"bar")},
 274    :                             {reinterpret_cast<const wchar_t*>(L"hello"),
 275  E :                              reinterpret_cast<const wchar_t*>(L"world")}};
 276    :  
 277  E :    base::Thread client_thread("client thread");
 278  E :    ASSERT_TRUE(client_thread.Start());
 279    :    client_thread.message_loop()->PostTask(
 280    :        FROM_HERE, base::Bind(&DoInvokeService, protocol, endpoint,
 281    :                              base::Unretained(&complete), 0, 0, SMALL_DUMP, 0,
 282    :                              nullptr, arraysize(crash_keys),
 283  E :                              base::Unretained(crash_keys), 0, nullptr));
 284    :    // In case the DoInvokeService fails, let's make sure we unblock ourselves.
 285    :    client_thread.message_loop()->PostTask(
 286    :        FROM_HERE,
 287  E :        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&blocking)));
 288  E :    blocking.Wait();
 289    :  
 290    :    // Either DoInvokeService failed (complete == true), or we are blocking in
 291    :    // BlockingService::SendDiagnosticReport (complete == false).
 292  E :    ASSERT_FALSE(complete);
 293    :  
 294    :    // Reduce the chance of false positives by giving the service call a chance to
 295    :    // complete. (It shouldn't.)
 296  E :    ::Sleep(100);
 297    :  
 298  E :    base::Thread stop_thread("stop thread");
 299  E :    ASSERT_TRUE(stop_thread.Start());
 300    :    stop_thread.message_loop()->PostTask(
 301  E :        FROM_HERE, base::Bind(&ServiceBridge::Stop, base::Unretained(&instance)));
 302  E :    ASSERT_FALSE(complete);
 303    :  
 304    :    // Stop is waiting for the pending call to complete. Let's unblock it now.
 305  E :    release_call.Signal();
 306    :  
 307    :    // This will not return until the ServiceBridge::Stop has completed.
 308  E :    stop_thread.Stop();
 309  E :    ASSERT_TRUE(complete);
 310  E :  }
 311    :  
 312    :  }  // namespace kasko

Coverage information generated Thu Jan 14 17:40:38 2016.