1 // Copyright (c) 2012 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 <errno.h> 6 #include <sys/file.h> 7 8 #include "base/basictypes.h" 9 #include "base/containers/hash_tables.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "chrome/browser/chromeos/external_metrics.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 namespace chromeos { // Need this because of the FRIEND_TEST 15 16 class ExternalMetricsTest : public testing::Test { 17 }; 18 19 // Because the metrics service is not essential, errors will not cause the 20 // program to terminate. However, the errors produce logs. 21 22 #define MAXLENGTH ExternalMetrics::kMetricsMessageMaxLength 23 24 static void SendMessage(const char* path, const char* name, const char* value) { 25 int fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0666); 26 int32 l = strlen(name) + strlen(value) + 2 + sizeof(l); 27 size_t num_bytes = 0; 28 num_bytes += write(fd, &l, sizeof(l)); 29 num_bytes += write(fd, name, strlen(name) + 1); 30 num_bytes += write(fd, value, strlen(value) + 1); 31 EXPECT_EQ(num_bytes, sizeof(l) + strlen(name) + strlen(value) + 2); 32 close(fd); 33 } 34 35 static scoped_ptr<std::string> received_name; 36 static scoped_ptr<std::string> received_value; 37 int received_count = 0; 38 39 static void ReceiveMessage(const char* name, const char* value) { 40 received_name.reset(new std::string(name)); 41 received_value.reset(new std::string(value)); 42 received_count++; 43 } 44 45 static void CheckMessage(const char* name, const char* value, int count) { 46 EXPECT_EQ(*received_name.get(), name); 47 EXPECT_EQ(*received_value.get(), value); 48 EXPECT_EQ(received_count, count); 49 } 50 51 TEST(ExternalMetricsTest, ParseExternalMetricsFile) { 52 const char *histogram_data[] = { 53 "BootTime 9500 0 20000 50", 54 "BootTime 10000 0 20000 50", 55 "BootTime 9200 0 20000 50", 56 "ConnmanIdle 1000 0 2000 20", 57 "ConnmanIdle 1200 0 2000 20", 58 "ConnmanDisconnect 1000 0 2000 20", 59 "ConnmanFailure 1000 0 2000 20", 60 "ConnmanFailure 13000 2000 20", 61 "ConnmanAssociation 1000 0 2000 20", 62 "ConnmanConfiguration 1000 0 2000 20", 63 "ConnmanOffline 1000 0 2000 20", 64 "ConnmanOnline 1000 0 2000 20", 65 "ConnmanOffline 2000 0 2000 20", 66 "ConnmanReady 33000 0 100000 50", 67 "ConnmanReady 44000 0 100000 50", 68 "ConnmanReady 22000 0 100000 50", 69 }; 70 int nhist = ARRAYSIZE_UNSAFE(histogram_data); 71 int32 i; 72 const char* path = "/tmp/.chromeos-metrics"; 73 scoped_refptr<chromeos::ExternalMetrics> 74 external_metrics(new chromeos::ExternalMetrics()); 75 external_metrics->test_recorder_ = &ReceiveMessage; 76 external_metrics->test_path_ = base::FilePath(path); 77 EXPECT_TRUE(unlink(path) == 0 || errno == ENOENT); 78 79 // Sends a few valid messages. Once in a while, collects them and checks the 80 // last message. We don't want to check every single message because we also 81 // want to test the ability to deal with a file containing more than one 82 // message. 83 for (i = 0; i < nhist; i++) { 84 SendMessage(path, "histogram", histogram_data[i]); 85 if (i % 3 == 2) { 86 external_metrics->CollectEvents(); 87 CheckMessage("histogram", histogram_data[i], i + 1); 88 } 89 } 90 91 // Sends a crash message. 92 int expect_count = nhist; 93 SendMessage(path, "crash", "user"); 94 external_metrics->CollectEvents(); 95 CheckMessage("crash", "user", ++expect_count); 96 97 // Sends a message that's too large. 98 char b[MAXLENGTH + 100]; 99 for (i = 0; i < MAXLENGTH + 99; i++) { 100 b[i] = 'x'; 101 } 102 b[i] = '\0'; 103 SendMessage(path, b, "yyy"); 104 // Expect logged errors about bad message size. 105 external_metrics->CollectEvents(); 106 EXPECT_EQ(expect_count, received_count); 107 108 // Sends a malformed message (first string is not null-terminated). 109 i = 100 + sizeof(i); 110 int fd = open(path, O_CREAT | O_WRONLY, 0666); 111 EXPECT_GT(fd, 0); 112 EXPECT_EQ(static_cast<int>(sizeof(i)), write(fd, &i, sizeof(i))); 113 EXPECT_EQ(i, write(fd, b, i)); 114 EXPECT_EQ(0, close(fd)); 115 116 external_metrics->CollectEvents(); 117 EXPECT_EQ(expect_count, received_count); 118 119 // Sends a malformed message (second string is not null-terminated). 120 b[50] = '\0'; 121 fd = open(path, O_CREAT | O_WRONLY, 0666); 122 EXPECT_GT(fd, 0); 123 EXPECT_EQ(static_cast<int>(sizeof(i)), write(fd, &i, sizeof(i))); 124 EXPECT_EQ(i, write(fd, b, i)); 125 EXPECT_EQ(0, close(fd)); 126 127 external_metrics->CollectEvents(); 128 EXPECT_EQ(expect_count, received_count); 129 130 // Checks that we survive when file doesn't exist. 131 EXPECT_EQ(0, unlink(path)); 132 external_metrics->CollectEvents(); 133 EXPECT_EQ(expect_count, received_count); 134 } 135 136 } // namespace chromeos 137