Home | History | Annotate | Download | only in chromeos
      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