Bug 1299756 - VideoPuppeteer: Use played ranges in determining time remaining. Relax playback done check. r=maja_zf
authorBryce Van Dyk <bvandyk@mozilla.com>
Thu, 01 Sep 2016 14:51:19 +1200
changeset 312365 8f3ac8b34fa9d8b6cdd1783022e257b18913b9cf
parent 312364 1f2c133d78b14c9b3faea5c31f70b94e90df0b8d
child 312367 e12415c1560179174bd3bdaca11dd20e6b97d35a
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmaja_zf
bugs1299756
milestone51.0a1
Bug 1299756 - VideoPuppeteer: Use played ranges in determining time remaining. Relax playback done check. r=maja_zf The VideoPuppeteer now uses played ranges where possible to calculate the remaining time. It will also use the played ranges to determine the expected duration where possible. This is more accurate than using the time when the tests first poll the video. The first poll time was previously self._start_time, but I've renamed this to self._first_seen_time, to reduce ambiguity -- the video may have started playing before this time. The playback_done function has had it's remaining time check relaxed. Previously it was possible to skip over the window where a video would be considered complete, that window is now expanded so that if the start threshold is passed the video is considered played. A concrete example: the tests could play a 90 second video, but the duration of the test is set to 60 so only part of the video need be played back before the test completes. If a 1 second interval was used in the tests there would be a window between 59 to 61 seconds during which if the video were polled it would be considered complete. However, due to latency polling may not take place in this window, leading to racy fails. Now the tests will consider any point beyond 59 seconds to be complete. MozReview-Commit-ID: J6DpqCbZxUg
dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
--- a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
@@ -62,18 +62,18 @@ class VideoPuppeteer(object):
         self.marionette = marionette
         self.test_url = url
         self.interval = interval
         self.stall_wait_time = stall_wait_time
         self.timeout = timeout
         self._set_duration = set_duration
         self.video = None
         self.expected_duration = 0
-        self._start_time = 0
-        self._start_wall_time = 0
+        self._first_seen_time = 0
+        self._first_seen_wall_time = 0
         wait = Wait(self.marionette, timeout=self.timeout)
         with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
             self.marionette.navigate(self.test_url)
             self.marionette.execute_script("""
                 log('URL: {0}');""".format(self.test_url))
             verbose_until(wait, self,
                           expected.element_present(By.TAG_NAME, 'video'))
             videos_found = self.marionette.find_elements(By.CSS_SELECTOR,
@@ -91,18 +91,18 @@ class VideoPuppeteer(object):
             if autostart:
                 self.start()
 
     def start(self):
         # To get an accurate expected_duration, playback must have started
         wait = Wait(self, timeout=self.timeout)
         verbose_until(wait, self, playback_started,
                       "Check if video has played some range")
-        self._start_time = self.current_time
-        self._start_wall_time = clock()
+        self._first_seen_time = self.current_time
+        self._first_seen_wall_time = clock()
         self.update_expected_duration()
 
     def update_expected_duration(self):
         """
         Update the duration of the target video at self.test_url (in seconds).
 
         expected_duration represents the following: how long do we expect
         playback to last before we consider the video to be 'complete'?
@@ -110,24 +110,31 @@ class VideoPuppeteer(object):
         expected_duration is set to n.
         """
         # self.duration is the duration of whatever is playing right now.
         # In this case, we assume the video element always shows the same
         # stream throughout playback (i.e. the are no ads spliced into the main
         # video, for example), so self.duration is the duration of the main
         # video.
         video_duration = self.duration
-        set_duration = self._set_duration
+        # Do our best to figure out where the video started playing
+        played_ranges = self.played
+        if played_ranges.length > 0:
+            # If we have a range we should only have on continuous range
+            assert played_ranges.length == 1
+            start_position = played_ranges.start(0)
+        else:
+            # If we don't have a range we should have a current time
+            start_position = self._first_seen_time
         # In case video starts at t > 0, adjust target time partial playback
-        if self._set_duration and self._start_time:
-            set_duration += self._start_time
-        if 0 < set_duration < video_duration:
-            self.expected_duration = set_duration
+        remaining_video = video_duration - start_position
+        if 0 < self._set_duration < remaining_video:
+            self.expected_duration = self._set_duration
         else:
-            self.expected_duration = video_duration
+            self.expected_duration = remaining_video
 
     def get_debug_lines(self):
         """
         Get Firefox internal debugging for the video element.
 
         :return: A text string that has Firefox-internal debugging information.
         """
         with self.marionette.using_context('chrome'):
@@ -166,17 +173,21 @@ class VideoPuppeteer(object):
             'return arguments[0].wrappedJSObject.currentTime;') or 0
 
     @property
     def remaining_time(self):
         """
         :return: How much time is remaining given the duration of the video
             and the duration that has been set.
         """
-        return self.expected_duration - self.current_time
+        played_ranges = self.played
+        # Playback should be in one range (as tests do not currently seek).
+        assert played_ranges.length == 1
+        played_duration = self.played.end(0) - self.played.start(0)
+        return self.expected_duration - played_duration
 
     @property
     def played(self):
         """
         :return: A TimeRanges objected containing the played time ranges.
         """
         raw_time_ranges = self.execute_video_script(
             'var played = arguments[0].wrappedJSObject.played;'
@@ -237,18 +248,18 @@ class VideoPuppeteer(object):
     def lag(self):
         """
         :return: The difference in time between where the video is currently
             playing and where it should be playing given the time we started
             the video.
         """
         # Note that self.current_time could temporarily refer to a
         # spliced-in ad
-        elapsed_current_time = self.current_time - self._start_time
-        elapsed_wall_time = clock() - self._start_wall_time
+        elapsed_current_time = self.current_time - self._first_seen_time
+        elapsed_wall_time = clock() - self._first_seen_wall_time
         return elapsed_wall_time - elapsed_current_time
 
     def measure_progress(self):
         initial = self.current_time
         sleep(1)
         return self.current_time - initial
 
     def execute_video_script(self, script):
@@ -336,18 +347,17 @@ def playback_done(video):
     we are essentially done. If this happens to be last time we are polled
     before the video ends, we won't get another chance.
 
     :param video: The VideoPuppeteer instance that we are interested in.
 
     :return: True if we are close enough to the end of playback; False
         otherwise.
     """
-    remaining_time = video.remaining_time
-    if abs(remaining_time) < video.interval:
+    if video.remaining_time < video.interval:
         return True
 
     # Check to see if the video has stalled. Accumulate the amount of lag
     # since the video started, and if it is too high, then raise.
     if video.stall_wait_time and (video.lag > video.stall_wait_time):
         raise VideoException('Video %s stalled.\n%s' % (video.video_url,
                                                         video))