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/common/child_process_logging.h" 6 7 #include <map> 8 #include <string> 9 10 #import <Foundation/Foundation.h> 11 12 #include "base/debug/crash_logging.h" 13 #include "base/logging.h" 14 #include "base/strings/stringprintf.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/platform_test.h" 17 18 typedef PlatformTest ChildProcessLoggingTest; 19 20 namespace { 21 22 // Class to mock breakpad's setkeyvalue/clearkeyvalue functions needed for 23 // SetActiveRendererURLImpl. 24 // The Keys are stored in a static dictionary and methods are provided to 25 // verify correctness. 26 class MockBreakpadKeyValueStore { 27 public: 28 MockBreakpadKeyValueStore() { 29 // Only one of these objects can be active at once. 30 DCHECK(dict == NULL); 31 dict = new std::map<std::string, std::string>; 32 } 33 34 ~MockBreakpadKeyValueStore() { 35 // Only one of these objects can be active at once. 36 DCHECK(dict != NULL); 37 delete dict; 38 dict = NULL; 39 } 40 41 static void SetKeyValue(const base::StringPiece& key, 42 const base::StringPiece& value) { 43 DCHECK(dict != NULL); 44 (*dict)[key.as_string()] = value.as_string(); 45 } 46 47 static void ClearKeyValue(const base::StringPiece& key) { 48 DCHECK(dict != NULL); 49 dict->erase(key.as_string()); 50 } 51 52 size_t CountDictionaryEntries() { 53 return dict->size(); 54 } 55 56 bool VerifyDictionaryContents(const std::string& url) { 57 using child_process_logging::kMaxNumCrashURLChunks; 58 using child_process_logging::kMaxNumURLChunkValueLength; 59 using child_process_logging::kUrlChunkFormatStr; 60 61 size_t num_url_chunks = CountDictionaryEntries(); 62 EXPECT_LE(num_url_chunks, kMaxNumCrashURLChunks); 63 64 std::string accumulated_url; 65 for (size_t i = 0; i < num_url_chunks; ++i) { 66 // URL chunk names are 1-based. 67 std::string key = base::StringPrintf(kUrlChunkFormatStr, i + 1); 68 std::string value = (*dict)[key]; 69 EXPECT_GT(value.length(), 0u); 70 EXPECT_LE(value.length(), 71 static_cast<size_t>(kMaxNumURLChunkValueLength)); 72 accumulated_url += value; 73 } 74 75 return url == accumulated_url; 76 } 77 78 private: 79 static std::map<std::string, std::string>* dict; 80 DISALLOW_COPY_AND_ASSIGN(MockBreakpadKeyValueStore); 81 }; 82 83 // static 84 std::map<std::string, std::string>* MockBreakpadKeyValueStore::dict; 85 86 } // namespace 87 88 // Call through to SetActiveURLImpl using the functions from 89 // MockBreakpadKeyValueStore. 90 void SetActiveURLWithMock(const GURL& url) { 91 using child_process_logging::SetActiveURLImpl; 92 93 base::debug::SetCrashKeyValueFuncT setFunc = 94 MockBreakpadKeyValueStore::SetKeyValue; 95 base::debug::ClearCrashKeyValueFuncT clearFunc = 96 MockBreakpadKeyValueStore::ClearKeyValue; 97 98 SetActiveURLImpl(url, setFunc, clearFunc); 99 } 100 101 TEST_F(ChildProcessLoggingTest, TestUrlSplitting) { 102 using child_process_logging::kMaxNumCrashURLChunks; 103 using child_process_logging::kMaxNumURLChunkValueLength; 104 105 const std::string short_url("http://abc/"); 106 std::string long_url("http://"); 107 std::string overflow_url("http://"); 108 109 long_url += std::string(kMaxNumURLChunkValueLength * 2, 'a'); 110 long_url += "/"; 111 112 int max_num_chars_stored_in_dump = kMaxNumURLChunkValueLength * 113 kMaxNumCrashURLChunks; 114 overflow_url += std::string(max_num_chars_stored_in_dump + 1, 'a'); 115 overflow_url += "/"; 116 117 // Check that Clearing NULL URL works. 118 MockBreakpadKeyValueStore mock; 119 SetActiveURLWithMock(GURL()); 120 EXPECT_EQ(0u, mock.CountDictionaryEntries()); 121 122 // Check that we can set a URL. 123 SetActiveURLWithMock(GURL(short_url.c_str())); 124 EXPECT_TRUE(mock.VerifyDictionaryContents(short_url)); 125 EXPECT_EQ(1u, mock.CountDictionaryEntries()); 126 SetActiveURLWithMock(GURL()); 127 EXPECT_EQ(0u, mock.CountDictionaryEntries()); 128 129 // Check that we can replace a long url with a short url. 130 SetActiveURLWithMock(GURL(long_url.c_str())); 131 EXPECT_TRUE(mock.VerifyDictionaryContents(long_url)); 132 SetActiveURLWithMock(GURL(short_url.c_str())); 133 EXPECT_TRUE(mock.VerifyDictionaryContents(short_url)); 134 SetActiveURLWithMock(GURL()); 135 EXPECT_EQ(0u, mock.CountDictionaryEntries()); 136 137 138 // Check that overflow works correctly. 139 SetActiveURLWithMock(GURL(overflow_url.c_str())); 140 EXPECT_TRUE(mock.VerifyDictionaryContents( 141 overflow_url.substr(0, max_num_chars_stored_in_dump))); 142 SetActiveURLWithMock(GURL()); 143 EXPECT_EQ(0u, mock.CountDictionaryEntries()); 144 } 145