// Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Chris Demetriou // // This file contains the unit tests for the ProfileData class. #if defined HAVE_STDINT_H #include // to get uintptr_t #elif defined HAVE_INTTYPES_H #include // another place uintptr_t might be defined #endif #include #include #include #include #include #include "profiledata.h" #include "base/commandlineflags.h" #include "base/logging.h" using std::string; // Some helpful macros for the test class #define EXPECT_TRUE(cond) CHECK(cond) #define EXPECT_FALSE(cond) CHECK(!(cond)) #define EXPECT_EQ(a, b) CHECK_EQ(a, b) #define EXPECT_GT(a, b) CHECK_GT(a, b) #define EXPECT_LT(a, b) CHECK_LT(a, b) #define EXPECT_GE(a, b) CHECK_GE(a, b) #define EXPECT_LE(a, b) CHECK_LE(a, b) #define EXPECT_STREQ(a, b) CHECK(strcmp(a, b) == 0) #define TEST_F(cls, fn) void cls :: fn() namespace { // must be the same as with ProfileData::Slot. typedef uintptr_t ProfileDataSlot; // Quick and dirty function to make a number into a void* for use in a // sample. inline void* V(intptr_t x) { return reinterpret_cast(x); } class ProfileDataChecker { public: ProfileDataChecker() { const char* tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; mkdir(tmpdir, 0755); // if necessary filename_ = string(tmpdir) + "/profiledata_unittest.tmp"; } string filename() const { return filename_; } void Check(const ProfileDataSlot* slots, int num_slots) { size_t num_bytes = num_slots * sizeof slots[0]; char* filedata = new char[num_bytes]; int fd = open(filename_.c_str(), O_RDONLY); EXPECT_GE(fd, 0); ssize_t numread = read(fd, filedata, num_bytes); EXPECT_EQ(numread, num_bytes); EXPECT_EQ(0, memcmp(slots, filedata, num_bytes)); close(fd); delete[] filedata; } private: string filename_; }; class ProfileDataTest { protected: void ExpectStopped() { EXPECT_FALSE(collector_.enabled()); } void ExpectRunningSamples(int samples) { ProfileData::State state; collector_.GetCurrentState(&state); EXPECT_TRUE(state.enabled); EXPECT_EQ(samples, state.samples_gathered); } void ExpectSameState(const ProfileData::State& before, const ProfileData::State& after) { EXPECT_EQ(before.enabled, after.enabled); EXPECT_EQ(before.samples_gathered, after.samples_gathered); EXPECT_EQ(before.start_time, after.start_time); EXPECT_STREQ(before.profile_name, after.profile_name); } ProfileData collector_; ProfileDataChecker checker_; private: // The tests to run void OpsWhenStopped(); void StartStopEmpty(); void StartWhenStarted(); void StartStopEmpty2(); void CollectOne(); void CollectTwoMatching(); void CollectTwoFlush(); public: #define RUN(test) do { \ printf("Running %s\n", #test); \ ProfileDataTest pdt; \ pdt.test(); \ } while (0) static int RUN_ALL_TESTS() { RUN(OpsWhenStopped); RUN(StartStopEmpty); RUN(StartWhenStarted); RUN(StartStopEmpty2); RUN(CollectOne); RUN(CollectTwoMatching); RUN(CollectTwoFlush); return 0; } }; // Check that various operations are safe when stopped. TEST_F(ProfileDataTest, OpsWhenStopped) { ExpectStopped(); EXPECT_FALSE(collector_.enabled()); // Verify that state is disabled, all-empty/all-0 ProfileData::State state_before; collector_.GetCurrentState(&state_before); EXPECT_FALSE(state_before.enabled); EXPECT_EQ(0, state_before.samples_gathered); EXPECT_EQ(0, state_before.start_time); EXPECT_STREQ("", state_before.profile_name); // Safe to call stop again. collector_.Stop(); // Safe to call FlushTable. collector_.FlushTable(); // Safe to call Add. const void *trace[] = { V(100), V(101), V(102), V(103), V(104) }; collector_.Add(arraysize(trace), trace); ProfileData::State state_after; collector_.GetCurrentState(&state_after); ExpectSameState(state_before, state_after); } // Start and Stop, collecting no samples. Verify output contents. TEST_F(ProfileDataTest, StartStopEmpty) { const int frequency = 1; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; ExpectStopped(); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency)); ExpectRunningSamples(0); collector_.Stop(); ExpectStopped(); checker_.Check(slots, arraysize(slots)); } // Start after already started. Should return false and not impact // collected data or state. TEST_F(ProfileDataTest, StartWhenStarted) { const int frequency = 1; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency)); ProfileData::State state_before; collector_.GetCurrentState(&state_before); CHECK(!collector_.Start("foobar", frequency * 2)); ProfileData::State state_after; collector_.GetCurrentState(&state_after); ExpectSameState(state_before, state_after); collector_.Stop(); ExpectStopped(); checker_.Check(slots, arraysize(slots)); } // Like StartStopEmpty, but uses a different file name and frequency. TEST_F(ProfileDataTest, StartStopEmpty2) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; ExpectStopped(); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency)); ExpectRunningSamples(0); collector_.Stop(); ExpectStopped(); checker_.Check(slots, arraysize(slots)); } TEST_F(ProfileDataTest, CollectOne) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 1, 5, 100, 101, 102, 103, 104, // our sample 0, 1, 0 // binary trailer }; ExpectStopped(); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency)); ExpectRunningSamples(0); const void *trace[] = { V(100), V(101), V(102), V(103), V(104) }; collector_.Add(arraysize(trace), trace); ExpectRunningSamples(1); collector_.Stop(); ExpectStopped(); checker_.Check(slots, arraysize(slots)); } TEST_F(ProfileDataTest, CollectTwoMatching) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 2, 5, 100, 201, 302, 403, 504, // our two samples 0, 1, 0 // binary trailer }; ExpectStopped(); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency)); ExpectRunningSamples(0); for (int i = 0; i < 2; ++i) { const void *trace[] = { V(100), V(201), V(302), V(403), V(504) }; collector_.Add(arraysize(trace), trace); ExpectRunningSamples(i + 1); } collector_.Stop(); ExpectStopped(); checker_.Check(slots, arraysize(slots)); } TEST_F(ProfileDataTest, CollectTwoFlush) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 1, 5, 100, 201, 302, 403, 504, // first sample (flushed) 1, 5, 100, 201, 302, 403, 504, // second identical sample 0, 1, 0 // binary trailer }; ExpectStopped(); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency)); ExpectRunningSamples(0); const void *trace[] = { V(100), V(201), V(302), V(403), V(504) }; collector_.Add(arraysize(trace), trace); ExpectRunningSamples(1); collector_.FlushTable(); collector_.Add(arraysize(trace), trace); ExpectRunningSamples(2); collector_.Stop(); ExpectStopped(); checker_.Check(slots, arraysize(slots)); } } // namespace int main(int argc, char** argv) { int rc = ProfileDataTest::RUN_ALL_TESTS(); printf("%s\n", rc == 0 ? "PASS" : "FAIL"); return rc; }