stopwatch_unittest.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <util/stopwatch.h>
  15. #include <util/stopwatch_impl.h>
  16. #include <gtest/gtest.h>
  17. #include <unistd.h>
  18. namespace {
  19. using namespace isc;
  20. using namespace isc::util;
  21. using namespace boost::posix_time;
  22. /// @brief @c StopwatchImpl mock object.
  23. ///
  24. /// This class derives from the @c StopwatchImpl to override the
  25. /// @c StopwatchImpl::getCurrentTime. This method is internally called by
  26. /// the @c StopwatchImpl to determine the current time. By providing the
  27. /// implementation of this method which returns the fixed (well known)
  28. /// timestamp value we can obtain the deterministic values from the accessors
  29. /// of this class.
  30. ///
  31. /// This class also includes some convenience methods to return the time
  32. /// durations in milliseconds.
  33. class StopwatchMock : public StopwatchImpl {
  34. public:
  35. /// @brief Constructor.
  36. ///
  37. /// @param ref_time Reference time, i.e. the arbitrary time value from
  38. /// which time is measured. The @c current_time_ value returned by the
  39. /// @c StopwatchMock::getCurrentTime is initialized to this value.
  40. /// Subsequent calls to the @c StopwatchMock::ffwd move the value of
  41. /// the @c current_time_ forward.
  42. StopwatchMock(const ptime& ref_time);
  43. /// @brief Fast forward time.
  44. ///
  45. /// Moves the value of the @c current_time_ forward by the specified
  46. /// number of milliseconds. As a result the timestamp returned by the
  47. /// @c StopwatchMock::getCurrentTime moves by this value. This simulates
  48. /// the time progress.
  49. ///
  50. /// @param ms Specifies the number of milliseconds to move current time.
  51. void ffwd(const uint32_t ms);
  52. /// @brief Returns the last duration in milliseconds.
  53. uint32_t getLastDurationInMs() const;
  54. /// @brief Returns the total duration in milliseconds.
  55. uint32_t getTotalDurationInMs() const;
  56. protected:
  57. /// @brief Returs the current time.
  58. ///
  59. /// This method returns the fixed @c current_time_ timestamp.
  60. virtual ptime getCurrentTime() const;
  61. private:
  62. /// @brief Holds the current time to be returned by the
  63. /// @c StopwatchMock::getCurrentTime.
  64. ptime current_time_;
  65. };
  66. StopwatchMock::StopwatchMock(const ptime& ref_time)
  67. : StopwatchImpl(), current_time_(ref_time) {
  68. }
  69. void
  70. StopwatchMock::ffwd(const uint32_t ms) {
  71. current_time_ += milliseconds(ms);
  72. }
  73. uint32_t
  74. StopwatchMock::getLastDurationInMs() const {
  75. return (getLastDuration().total_milliseconds());
  76. }
  77. uint32_t
  78. StopwatchMock::getTotalDurationInMs() const {
  79. return (getTotalDuration().total_milliseconds());
  80. }
  81. ptime
  82. StopwatchMock::getCurrentTime() const {
  83. return (current_time_);
  84. }
  85. /// @brief Test fixture class for testing @c StopwatchImpl.
  86. class StopwatchTest : public ::testing::Test {
  87. protected:
  88. /// @brief Set up the test.
  89. ///
  90. /// Initializes the reference time to be used to create the instances
  91. /// of the @c StopwatchMock objects.
  92. virtual void SetUp();
  93. /// @brief Holds the reference time to be used to create the instances
  94. /// of the @c StopwatchMock objects.
  95. ptime ref_time_;
  96. };
  97. void
  98. StopwatchTest::SetUp() {
  99. ref_time_ = microsec_clock::universal_time();
  100. }
  101. /// This test checks the behavior of the stopwatch when it is started
  102. /// and stopped multiple times. It uses the StopwatchMock object to
  103. /// control the "time flow" by setting the current time to arbitrary
  104. /// values using the StopwatchMock::ffwd. In addition, this test
  105. /// checks that the stopwatch can be reset.
  106. TEST_F(StopwatchTest, multipleMeasurements) {
  107. StopwatchMock stopwatch(ref_time_);
  108. // The stopwatch shouldn't automatically start. The initial
  109. // durations should be set to 0.
  110. EXPECT_EQ(0, stopwatch.getLastDurationInMs());
  111. EXPECT_EQ(0, stopwatch.getTotalDurationInMs());
  112. stopwatch.start();
  113. // Even though the stopwatch is started, the time is still set to
  114. // the initial value. The durations should not be affected.
  115. EXPECT_EQ(0, stopwatch.getLastDurationInMs());
  116. EXPECT_EQ(0, stopwatch.getTotalDurationInMs());
  117. // Move the time by 10 ms.
  118. stopwatch.ffwd(10);
  119. // It should be possible to retrieve the durations even when the
  120. // stopwatch is running.
  121. EXPECT_EQ(10, stopwatch.getLastDurationInMs());
  122. EXPECT_EQ(10, stopwatch.getTotalDurationInMs());
  123. // Now stop it and make sure that the same values are returned.
  124. stopwatch.stop();
  125. EXPECT_EQ(10, stopwatch.getLastDurationInMs());
  126. EXPECT_EQ(10, stopwatch.getTotalDurationInMs());
  127. // Start it again, but don't move the time forward yet.
  128. stopwatch.start();
  129. // The new duration should be 0, but the total should be equal to
  130. // the previously measured duration.
  131. EXPECT_EQ(0, stopwatch.getLastDurationInMs());
  132. EXPECT_EQ(10, stopwatch.getTotalDurationInMs());
  133. // Move time by 5 ms.
  134. stopwatch.ffwd(5);
  135. // New measured duration should be 5 ms. The total should be 15 ms.
  136. EXPECT_EQ(5, stopwatch.getLastDurationInMs());
  137. EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
  138. // Stop it again and make sure the values returned are the same.
  139. stopwatch.stop();
  140. EXPECT_EQ(5, stopwatch.getLastDurationInMs());
  141. EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
  142. // Move the time forward while the stopwatch is stopped.
  143. stopwatch.ffwd(8);
  144. // The measured values should not be affected.
  145. EXPECT_EQ(5, stopwatch.getLastDurationInMs());
  146. EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
  147. // Stop should be no-op in this case.
  148. stopwatch.stop();
  149. EXPECT_EQ(5, stopwatch.getLastDurationInMs());
  150. EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
  151. // Start the stopwatch again.
  152. stopwatch.start();
  153. // Move time by 3 ms.
  154. stopwatch.ffwd(3);
  155. // Since the stopwatch is running, the measured duration should
  156. // get updated again.
  157. EXPECT_EQ(3, stopwatch.getLastDurationInMs());
  158. EXPECT_EQ(18, stopwatch.getTotalDurationInMs());
  159. // Move the time by 2 ms.
  160. stopwatch.ffwd(2);
  161. // Start should be no-op in this case.
  162. stopwatch.start();
  163. // But the durations should be updated.
  164. EXPECT_EQ(5, stopwatch.getLastDurationInMs());
  165. EXPECT_EQ(20, stopwatch.getTotalDurationInMs());
  166. // Make sure we can reset.
  167. stopwatch.reset();
  168. EXPECT_EQ(0, stopwatch.getLastDurationInMs());
  169. EXPECT_EQ(0, stopwatch.getTotalDurationInMs());
  170. }
  171. // This test checks that the stopwatch works when the real clock is in use.
  172. TEST_F(StopwatchTest, realTime) {
  173. // Initially, the measured time should be 0.
  174. Stopwatch stopwatch;
  175. EXPECT_EQ(0, stopwatch.getMilliseconds());
  176. EXPECT_EQ(0, stopwatch.getTotalMilliseconds());
  177. // Start the stopwatch.
  178. stopwatch.start();
  179. // Sleep for 1 ms. The stopwatch should measure this duration.
  180. usleep(1000);
  181. stopwatch.stop();
  182. // The measured duration should be greater or equal 1 ms.
  183. long current_duration = stopwatch.getMilliseconds();
  184. EXPECT_GE(current_duration, 1);
  185. EXPECT_EQ(current_duration, stopwatch.getTotalMilliseconds());
  186. // Sleep for another 2 ms while the stopwatch is in the stopped state.
  187. usleep(2000);
  188. // In the stopped state, we should still have old durations measured.
  189. EXPECT_EQ(current_duration, stopwatch.getMilliseconds());
  190. EXPECT_EQ(current_duration, stopwatch.getTotalMilliseconds());
  191. // Start it again.
  192. stopwatch.start();
  193. // Slee for 1 ms.
  194. usleep(1000);
  195. // The durations should get updated as appropriate.
  196. current_duration = stopwatch.getMilliseconds();
  197. EXPECT_GE(stopwatch.getMilliseconds(), 1);
  198. EXPECT_GE(stopwatch.getTotalMilliseconds(), 2);
  199. }
  200. // Make sure that we can obtain the durations as microseconds.
  201. TEST_F(StopwatchTest, getMicroseconds) {
  202. Stopwatch stopwatch;
  203. stopwatch.start();
  204. usleep(1000);
  205. stopwatch.stop();
  206. long current_duration = stopwatch.getMicroseconds();
  207. EXPECT_GE(current_duration, 1000);
  208. EXPECT_EQ(current_duration, stopwatch.getTotalMicroseconds());
  209. }
  210. // Make sure that we can use the "autostart" option to start the time
  211. // measurement in the constructor.
  212. TEST_F(StopwatchTest, autostart) {
  213. Stopwatch stopwatch(true);
  214. usleep(1000);
  215. stopwatch.stop();
  216. EXPECT_GE(stopwatch.getMilliseconds(), 1);
  217. EXPECT_EQ(stopwatch.getMilliseconds(), stopwatch.getTotalMilliseconds());
  218. }
  219. } // end of anonymous namespace