コード例 #1
0
    def _get_webpage_result(self, url, host, protocol):
        s = requests.Session()
        headers = {
            "dnt": "1",
            "upgrade-insecure-requests": "1",
            "user-agent":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
            "accept":
            "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "sec-fetch-site": "none",
            "sec-fetch-mode": "navigate",
            "sec-fetch-user": "******",
            "sec-fetch-dest": "document",
            "accept-language": "en-GB,en-US;q=0.9,en;q=0.8",
        }

        start_time = time.time()
        try:
            r = s.get(url, headers=headers, timeout=self.download_timeout)
        except (ConnectionError, requests.ConnectionError) as e:
            return self._get_webpage_error("web-get", traceback=str(e))
        except requests.exceptions.ReadTimeout as e:
            return self._get_webpage_error("web-timeout", traceback=str(e))
        try:
            to_download = self._parse_html(r.text)
        except TypeError as e:
            return self._get_webpage_error("web-parse-rel", traceback=str(e))
        try:
            asset_download_metrics = self._download_assets(
                s, to_download, host, protocol)
        except TypeError as e:
            return self._get_webpage_error("web-assets", traceback=str(e))

        primary_download_size = len(r.text)
        asset_download_size = asset_download_metrics["asset_download_size"]
        elapsed_time = asset_download_metrics["completion_time"] - start_time
        download_rate = (primary_download_size +
                         asset_download_size) * 8 / elapsed_time
        failed_asset_downloads = asset_download_metrics[
            "failed_asset_downloads"]

        return WebpageMeasurementResult(
            id=self.id,
            url=url,
            download_rate=download_rate,
            download_rate_unit=NetworkUnit("bit/s"),
            download_size=primary_download_size + asset_download_size,
            download_size_unit=StorageUnit("B"),
            asset_count=len(to_download),
            failed_asset_downloads=failed_asset_downloads,
            elapsed_time=elapsed_time,
            elapsed_time_unit=TimeUnit("s"),
            errors=[],
        )
コード例 #2
0
    def _get_youtube_result(self, url):
        # Unique filename from process ID and timestamp
        file_dir = "{}/youtube-dl_{}".format(tempfile.gettempdir(),
                                             os.getpid())
        filename = "{}/youtube-dl_{}/{}".format(tempfile.gettempdir(),
                                                os.getpid(), int(time.time()))
        params = {
            "quiet": True,
            "progress_hooks": [self._store_progress_dicts_hook],
            "outtmpl": filename,
        }
        ydl = youtube_dl.YoutubeDL(params=params)
        try:
            ydl.extract_info(url)
        except youtube_dl.utils.ExtractorError as e:
            return self._get_youtube_error("youtube-extractor",
                                           traceback=str(e))
        except youtube_dl.utils.DownloadError as e:
            return self._get_youtube_error("youtube-download",
                                           traceback=str(e))
        try:
            # Extract size and duration from final progress step
            download_size = self.progress_dicts[-1]["total_bytes"]
            elapsed_time = self.progress_dicts[-1]["elapsed"]

            # Speed is only reported in non-final steps
            download_rate = self.progress_dicts[-2]["speed"] * 8
        except KeyError:
            return self._get_youtube_error("youtube-attribute",
                                           traceback=str(self.progress_dicts))
        except IndexError:
            return self._get_youtube_error("youtube-progress_length",
                                           traceback=str(self.progress_dicts))

        try:
            # Remove the created temp directory and all contents
            shutil.rmtree(file_dir)
        except FileNotFoundError as e:
            return self._get_youtube_error("youtube-no_directory",
                                           traceback=str(e))

        return YouTubeMeasurementResult(
            id=self.id,
            url=self.url,
            download_rate=download_rate,
            download_rate_unit=NetworkUnit("bit/s"),
            download_size=download_size,
            download_size_unit=StorageUnit("B"),
            elapsed_time=elapsed_time,
            elapsed_time_unit=TimeUnit("s"),
            errors=[],
        )
コード例 #3
0
    def measure(self, share=False):
        """
        @params share: Boolean determining whether to generate a PNG on speedtest.net displaying the result of the test.
        """
        try:
            s = speedtest.Speedtest()
        except speedtest.ConfigRetrievalError as e:
            return self._get_speedtest_error("speedtest-config",
                                             traceback=str(e))

        s.get_servers(self.servers)

        try:
            s.get_best_server()
        except speedtest.SpeedtestBestServerFailure as e:
            return self._get_speedtest_error("speedtest-best-server",
                                             traceback=str(e))

        s.download()
        s.upload()

        if share:
            try:
                s.results.share()
            except speedtest.ShareResultsConnectFailure as e:
                return self._get_speedtest_error("speedtest-share",
                                                 traceback=str(e))

        results_dict = s.results.dict()
        try:
            return SpeedtestdotnetMeasurementResult(
                id=self.id,
                download_rate=float(results_dict["download"]),
                download_rate_unit=NetworkUnit("bit/s"),
                upload_rate=float(results_dict["upload"]),
                upload_rate_unit=NetworkUnit("bit/s"),
                data_received=(results_dict["bytes_received"]),
                data_received_unit=StorageUnit("B"),
                latency=float(results_dict["ping"]),
                server_name=results_dict["server"]["name"],
                server_id=results_dict["server"]["id"],
                server_sponsor=results_dict["server"]["sponsor"],
                server_host=results_dict["server"]["host"],
                errors=[],
            )
        except ValueError as e:
            return self._get_speedtest_error("speedtest-convert",
                                             traceback=str(e))
コード例 #4
0
 def setUp(self) -> None:
     super().setUp()
     self.wpm = WebpageMeasurement("test", "http://validfakehost.com/test")
     self.simple_webpage_output = WebpageMeasurementResult(
         id="test",
         url="http://validfakehost.com/test",
         download_rate=100 / 1.00 * 8,
         download_rate_unit=NetworkUnit("bit/s"),
         download_size=100,
         download_size_unit=StorageUnit("B"),
         asset_count=123,
         failed_asset_downloads=0,
         elapsed_time=1.00,
         elapsed_time_unit=TimeUnit("s"),
         errors=[],
     )
     self.simple_asset_download_metrics = {
         "asset_download_size": 90,
         "failed_asset_downloads": 0,
         "completion_time": 2.00,
     }
     self.get_error_result = WebpageMeasurementResult(
         id="test",
         url="http://validfakehost.com/test",
         download_rate_unit=None,
         download_rate=None,
         download_size=None,
         download_size_unit=None,
         asset_count=None,
         failed_asset_downloads=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="web-get",
                 description=WEB_ERRORS.get("web-get", ""),
                 traceback="[Errno -2] Name or service not known",
             )
         ],
     )
コード例 #5
0
 def _get_url_result(self, thread_result):
     host = urllib.parse.urlparse(thread_result["url"]).netloc
     city = thread_result["location"]["city"]
     country = thread_result["location"]["country"]
     LatencyResult = LatencyMeasurement(self.id, host,
                                        count=PING_COUNT).measure()[0]
     return [
         NetflixFastThreadResult(
             id=self.id,
             host=host,
             city=city,
             country=country,
             download_size=thread_result["download_size"],
             download_size_unit=StorageUnit("B"),
             download_rate=thread_result["download_rate"],
             download_rate_unit=NetworkUnit("bit/s"),
             elapsed_time=thread_result["elapsed_time"],
             elapsed_time_unit=TimeUnit("s"),
             errors=[],
         ),
         LatencyResult,
     ]
コード例 #6
0
    def _get_latency_results(  # noqa: C901
        self, host, count=4, include_individual_results=False
    ):
        """Perform the latency measurement.

        :param host: The host name to perform the test against.
        :param count: The number of pings to determine latency with.
        :param include_individual_results: Should each of the
        individualised ping iterations be included in the results?
        :return: A list of `LatencyMeasurementResult` and
        `LatencyIndividualMeasurementResult` if individual results are
        enabled.
        """
        if host is None:
            return [self._get_latency_error("ping-no-server", host, traceback=None)]

        latency_out = subprocess.run(
            ["ping", "-c", "{c}".format(c=count), "{h}".format(h=host)],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            universal_newlines=True,
        )

        # Note: only this error cares about stderr, other issues will be evident in stdout
        if latency_out.returncode != 0:
            return [
                self._get_latency_error("ping-err", host, traceback=latency_out.stderr)
            ]

        try:
            latency_data = latency_out.stdout.split("\n")[-2]
        except IndexError:
            return [
                self._get_latency_error(
                    "ping-split", host, traceback=latency_out.stdout
                )
            ]

        matches = LATENCY_OUTPUT_REGEX.search(latency_data)
        try:
            match_data = matches.groupdict()
        except AttributeError:
            return [
                self._get_latency_error(
                    "ping-regex", host, traceback=latency_out.stdout
                )
            ]

        if len(match_data.keys()) != 4:
            return [
                self._get_latency_error(
                    "ping-regex", host, traceback=latency_out.stdout
                )
            ]
        match_data = matches.groupdict()

        try:
            maximum_latency = float(match_data.get("maximum_latency"))
        except (TypeError, ValueError):
            return [
                self._get_latency_error(
                    "ping-maximum-latency", host, traceback=latency_out.stdout
                )
            ]

        try:
            minimum_latency = float(match_data.get("minimum_latency"))
        except (TypeError, ValueError):
            return [
                self._get_latency_error(
                    "ping-minimum-latency", host, traceback=latency_out.stdout
                )
            ]

        try:
            average_latency = float(match_data.get("average_latency"))
        except (TypeError, ValueError):
            return [
                self._get_latency_error(
                    "ping-average-latency", host, traceback=latency_out.stdout
                )
            ]

        try:
            median_deviation = float(match_data.get("median_deviation"))
        except (TypeError, ValueError):
            return [
                self._get_latency_error(
                    "ping-median_deviation", host, traceback=latency_out.stdout
                )
            ]

        try:
            latency_data = latency_out.stdout.split("\n")[-3]
        except IndexError:
            return [
                self._get_latency_error(
                    "ping-split", host, traceback=latency_out.stdout
                )
            ]

        matches = LATENCY_PACKETS_REGEX.search(latency_data)
        try:
            match_data = matches.groupdict()
        except AttributeError:
            return [
                self._get_latency_error(
                    "ping-regex", host, traceback=latency_out.stdout
                )
            ]

        packets_transmitted = int(match_data.get("packets_transmitted"))
        packets_received = int(match_data.get("packets_received"))
        packet_loss = float(match_data.get("packet_loss"))
        elapsed_time = float(match_data.get("time"))
        elapsed_time_unit = match_data.get("time_unit")

        results = [
            LatencyMeasurementResult(
                id=self.id,
                host=host,
                minimum_latency=minimum_latency,
                average_latency=average_latency,
                maximum_latency=maximum_latency,
                median_deviation=median_deviation,
                packets_transmitted=packets_transmitted,
                packets_received=packets_received,
                packets_lost=packet_loss,
                packets_lost_unit=RatioUnit.percentage,
                elapsed_time=elapsed_time,
                elapsed_time_unit=TimeUnit(elapsed_time_unit),
                errors=[],
            )
        ]

        if include_individual_results:
            matches = LATENCY_INDIVIDUAL_PING_REGEX.findall(latency_out.stdout)
            for match in matches:
                results.append(
                    LatencyIndividualMeasurementResult(
                        id=self.id,
                        host=host,
                        errors=[],
                        packet_size=match[0],
                        packet_size_unit=StorageUnit(match[1].replace("bytes", "B")),
                        reverse_dns_address=match[2],
                        ip_address=match[3],
                        icmp_sequence=match[4],
                        time_to_live=match[5],
                        elapsed_time=match[6],
                        elapsed_time_unit=TimeUnit(match[7]),
                    )
                )

        return results
コード例 #7
0
    def _get_fast_result(self):
        s = requests.Session()
        try:
            resp = self._get_response(s)
        except ConnectionError as e:
            return self._get_netflix_error("netflix-response",
                                           traceback=str(e))

        try:
            script = re.search(r'<script src="(.*?)">', resp.text).group(1)
        except AttributeError:
            return self._get_netflix_error("netflix-script-regex",
                                           traceback=resp.text)

        try:
            script_resp = s.get(
                "https://fast.com{script}".format(script=script))
        except ConnectionError as e:
            return self._get_netflix_error("netflix-script-response",
                                           traceback=str(e))

        try:
            token = re.search(r'token:"(.*?)"', script_resp.text).group(1)
        except AttributeError:
            return self._get_netflix_error("netflix-token-regex",
                                           traceback=script_resp.text)

        try:
            self._query_api(s, token)
        except ConnectionError as e:
            return self._get_netflix_error("netflix-api-response",
                                           traceback=str(e))
        except json.decoder.JSONDecodeError as e:
            return self._get_netflix_error("netflix-api-json",
                                           traceback=str(e))
        except TypeError as e:
            return self._get_netflix_error("netflix-api-parse",
                                           traceback=str(e))
        except KeyError as e:
            return self._get_netflix_error("netflix-api-parse",
                                           traceback=str(e))

        try:
            conns = [
                self._get_connection(target["url"])
                for target in self.thread_results
            ]
        except ConnectionError as e:
            return self._get_netflix_error("netflix-connection",
                                           traceback=str(e))

        fast_data = self._manage_threads(conns)

        return NetflixFastMeasurementResult(
            id=self.id,
            download_rate=float(fast_data["speed_bits"]),
            download_rate_unit=NetworkUnit("bit/s"),
            download_size=float(fast_data["total"]),
            download_size_unit=StorageUnit("B"),
            asn=self.client_data["asn"],
            ip=self.client_data["ip"],
            isp=self.client_data["isp"],
            city=self.client_data["location"]["city"],
            country=self.client_data["location"]["country"],
            urlcount=self.urlcount,
            reason_terminated=fast_data["reason_terminated"],
            errors=[],
        )
コード例 #8
0
 def setUp(self) -> None:
     super().setUp()
     self.nft = NetflixFastMeasurement("1",
                                       urlcount=3,
                                       terminate_on_thread_complete=True)
     self.api_response_three = {
         "client": {
             "location": {
                 "city": "HBox City",
                 "country": "HBoxtopia"
             },
             "isp": "ServiceProvider",
             "asn": "0000",
             "ip": "0000:0000:000a:0000:0c00:0b00:a0a0:f0f0",
         },
         "targets": [
             {
                 "location": {
                     "city": "Foreign City One",
                     "country": "Foreign Country One",
                 },
                 "name": "https://afakeurl.1.notreal.net/speedtest",
                 "url": "https://afakeurl.1.notreal.net/speedtest",
             },
             {
                 "location": {
                     "city": "Foreign City Two",
                     "country": "Foreign Country Two",
                 },
                 "name": "https://afakeurl.2.notreal.net/speedtest",
                 "url": "https://afakeurl.2.notreal.net/speedtest",
             },
             {
                 "location": {
                     "city": "Foreign City Three",
                     "country": "Foreign Country Three",
                 },
                 "name": "https://afakeurl.3.notreal.net/speedtest",
                 "url": "https://afakeurl.3.notreal.net/speedtest",
             },
         ],
     }
     self.fast_data_three = {
         "speed_bits": 1234,
         "total": 4321,
         "reason_terminated": "fake_reason",
     }
     self.fast_result_three = NetflixFastMeasurementResult(
         id="1",
         download_rate=float(self.fast_data_three["speed_bits"]),
         download_rate_unit=NetworkUnit("bit/s"),
         download_size=float(self.fast_data_three["total"]),
         download_size_unit=StorageUnit("B"),
         asn=self.api_response_three["client"]["asn"],
         ip=self.api_response_three["client"]["ip"],
         isp=self.api_response_three["client"]["isp"],
         city=self.api_response_three["client"]["location"]["city"],
         country=self.api_response_three["client"]["location"]["country"],
         urlcount=3,
         reason_terminated=self.fast_data_three["reason_terminated"],
         errors=[],
     )
     self.thread_result_three_list = [
         [
             NetflixFastThreadResult(
                 id="1",
                 host="afakeurl.1.notreal.net",
                 city=self.api_response_three["targets"][0]["location"]
                 ["city"],
                 country=self.api_response_three["targets"][0]["location"]
                 ["country"],
                 download_size=0,
                 download_size_unit=StorageUnit("B"),
                 download_rate=0,
                 download_rate_unit=NetworkUnit("bit/s"),
                 elapsed_time=0,
                 elapsed_time_unit=TimeUnit("s"),
                 errors=[],
             ),
             LatencyMeasurementResult(
                 id="1",
                 host="afakeurl.1.notreal.net",
                 minimum_latency=0,
                 average_latency=0,
                 maximum_latency=0,
                 median_deviation=0,
                 packets_transmitted=0,
                 packets_received=0,
                 packets_lost=0,
                 packets_lost_unit=RatioUnit("%"),
                 elapsed_time=0,
                 elapsed_time_unit=TimeUnit("d"),
                 errors=[],
             ),
         ],
         [
             NetflixFastThreadResult(
                 id="1",
                 host="afakeurl.1.notreal.net",
                 city=self.api_response_three["targets"][1]["location"]
                 ["city"],
                 country=self.api_response_three["targets"][1]["location"]
                 ["country"],
                 download_size=0,
                 download_size_unit=StorageUnit("B"),
                 download_rate=0,
                 download_rate_unit=NetworkUnit("bit/s"),
                 elapsed_time=0,
                 elapsed_time_unit=TimeUnit("s"),
                 errors=[],
             ),
             LatencyMeasurementResult(
                 id="1",
                 host="afakeurl.1.notreal.net",
                 minimum_latency=0,
                 average_latency=0,
                 maximum_latency=0,
                 median_deviation=0,
                 packets_transmitted=0,
                 packets_received=0,
                 packets_lost=0,
                 packets_lost_unit=RatioUnit("%"),
                 elapsed_time=0,
                 elapsed_time_unit=TimeUnit("d"),
                 errors=[],
             ),
         ],
         [
             NetflixFastThreadResult(
                 id="1",
                 host="afakeurl.1.notreal.net",
                 city=self.api_response_three["targets"][2]["location"]
                 ["city"],
                 country=self.api_response_three["targets"][2]["location"]
                 ["country"],
                 download_size=0,
                 download_size_unit=StorageUnit("B"),
                 download_rate=0,
                 download_rate_unit=NetworkUnit("bit/s"),
                 elapsed_time=0,
                 elapsed_time_unit=TimeUnit("s"),
                 errors=[],
             ),
             LatencyMeasurementResult(
                 id="1",
                 host="afakeurl.1.notreal.net",
                 minimum_latency=0,
                 average_latency=0,
                 maximum_latency=0,
                 median_deviation=0,
                 packets_transmitted=0,
                 packets_received=0,
                 packets_lost=0,
                 packets_lost_unit=RatioUnit("%"),
                 elapsed_time=0,
                 elapsed_time_unit=TimeUnit("d"),
                 errors=[],
             ),
         ],
     ]
コード例 #9
0
 def setUp(self) -> None:
     super().setUp()
     self.id = "1"
     self.stdnm = SpeedtestdotnetMeasurement("1")
     self.sample_results_dict_valid = {
         "download": 93116804.64881887,
         "upload": 19256654.06593738,
         "ping": 17.054,
         "server": {
             "url": "http://fake.site:8080/speedtest/upload.php",
             "lat": "-33.8600",
             "lon": "151.2111",
             "name": "HonestyVille",
             "country": "Australia",
             "cc": "AU",
             "sponsor": "'Yes' HonestyBox",
             "id": "1267",
             "url2": "http://s1.fake.site:8080/speedtest/upload.php",
             "host": "fake.site:8080",
             "d": 53.70823411720704,
             "latency": 17.054,
         },
         "timestamp": "2020-03-11T07:09:52.890803Z",
         "bytes_sent": 25591808,
         "bytes_received": 116746522,
         "share": "http://www.faketest.net/result/9117363621.png",
         "client": {
             "ip": "101.166.54.134",
             "lat": "-33.4102",
             "lon": "151.4225",
             "isp": "HonestyBox Internet",
             "isprating": "3.7",
             "rating": "0",
             "ispdlavg": "0",
             "ispulavg": "0",
             "loggedin": "0",
             "country": "AU",
         },
     }
     self.sample_result_valid = SpeedtestdotnetMeasurementResult(
         id=self.id,
         download_rate=93116804.64881887,
         download_rate_unit=NetworkUnit("bit/s"),
         upload_rate=19256654.06593738,
         upload_rate_unit=NetworkUnit("bit/s"),
         data_received=116746522,
         data_received_unit=StorageUnit("B"),
         latency=17.054,
         server_name="HonestyVille",
         server_id="1267",
         server_sponsor="'Yes' HonestyBox",
         server_host="fake.site:8080",
         errors=[],
     )
     self.sample_result_configretrieval = SpeedtestdotnetMeasurementResult(
         id=self.id,
         download_rate=None,
         download_rate_unit=None,
         upload_rate=None,
         upload_rate_unit=None,
         data_received=None,
         data_received_unit=None,
         latency=None,
         server_name=None,
         server_id=None,
         server_sponsor=None,
         server_host=None,
         errors=[
             Error(
                 key="speedtest-config",
                 description=SPEEDTEST_ERRORS.get("speedtest-config", ""),
                 traceback="<urlopen error [Errno -3] Temporary failure in name resolution>",
             )
         ],
     )
     self.sample_result_bestserver = SpeedtestdotnetMeasurementResult(
         id=self.id,
         download_rate=None,
         download_rate_unit=None,
         upload_rate=None,
         upload_rate_unit=None,
         data_received=None,
         data_received_unit=None,
         latency=None,
         server_name=None,
         server_id=None,
         server_sponsor=None,
         server_host=None,
         errors=[
             Error(
                 key="speedtest-best-server",
                 description=SPEEDTEST_ERRORS.get("speedtest-best-server", ""),
                 traceback="Unable to connect to servers to test latency.",
             )
         ],
     )
     self.sample_result_share = SpeedtestdotnetMeasurementResult(
         id=self.id,
         download_rate=None,
         download_rate_unit=None,
         upload_rate=None,
         upload_rate_unit=None,
         data_received=None,
         data_received_unit=None,
         latency=None,
         server_name=None,
         server_id=None,
         server_sponsor=None,
         server_host=None,
         errors=[
             Error(
                 key="speedtest-share",
                 description=SPEEDTEST_ERRORS.get("speedtest-share", ""),
                 traceback="<urlopen error [Errno -3] Temporary failure in name resolution>",
             )
         ],
     )
コード例 #10
0
 def setUp(self) -> None:
     super().setUp()
     self.id = "1"
     self.test_url = "https://www.youtube.com/watch?v=1233zthJUf31MA"
     self.ytm = YouTubeMeasurement(self.id, self.test_url)
     self.mock_progress_dicts = [
         {
             "_eta_str": "Unknown ETA",
             "_percent_str": "  0.0%",
             "_speed_str": "Unknown speed",
             "_total_bytes_str": "123.4MiB",
             "downloaded_bytes": 1024,
             "elapsed": 0.13415765762329102,
             "eta": None,
             "filename":
             "/tmp/youtube-dl_7954/1596695025_Portland Protest.mp4",
             "speed": None,
             "status": "downloading",
             "tmpfilename":
             "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4.part",
             "total_bytes": 163492702,
         },
         {
             "_eta_str": "00:00",
             "_percent_str": "100.0%",
             "_speed_str": "12.34MiB/s",
             "_total_bytes_str": "123.4MiB",
             "downloaded_bytes": 163492702,
             "elapsed": 13.792589902877808,
             "eta": 0,
             "filename":
             "/tmp/youtube-dl_31918/1596679305_Portland Protest.mp4",
             "speed": 12345678.012500000,
             "status": "downloading",
             "tmpfilename":
             "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4.part",
             "total_bytes": 163492702,
         },
         {
             "_elapsed_str": "12:34",
             "_total_bytes_str": "123.4MiB",
             "downloaded_bytes": 123456789,
             "elapsed": 12.345678987654321,
             "filename": "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4",
             "status": "finished",
             "total_bytes": 123456789,
         },
     ]
     self.mock_progress_dicts_missing_attribute = [
         {
             "_eta_str": "Unknown ETA",
             "_percent_str": "  0.0%",
             "_speed_str": "Unknown speed",
             "_total_bytes_str": "123.4MiB",
             "downloaded_bytes": 1024,
             "elapsed": 0.13415765762329102,
             "eta": None,
             "filename":
             "/tmp/youtube-dl_7954/1596695025_Portland Protest.mp4",
             "speed": None,
             "status": "downloading",
             "tmpfilename":
             "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4.part",
             "total_bytes": 163492702,
         },
         {
             "_eta_str": "00:00",
             "_percent_str": "100.0%",
             "_speed_str": "12.34MiB/s",
             "_total_bytes_str": "123.4MiB",
             "downloaded_bytes": 163492702,
             "elapsed": 13.792589902877808,
             "eta": 0,
             "filename":
             "/tmp/youtube-dl_31918/1596679305_Portland Protest.mp4",
             "speed": 12345678.012500000,
             "status": "downloading",
             "tmpfilename":
             "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4.part",
             "total_bytes": 163492702,
         },
         {
             "_elapsed_str": "12:34",
             "_total_bytes_str": "123.4MiB",
             "downloaded_bytes": 123456789,
             "elapsed": 12.345678987654321,
             "filename": "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4",
             "status": "finished",
             "BADotal_bytes": 123456789,
         },
     ]
     self.mock_progress_dicts_only_final = [{
         "_elapsed_str": "12:34",
         "_total_bytes_str": "123.4MiB",
         "downloaded_bytes": 123456789,
         "elapsed": 12.345678987654321,
         "filename": "/tmp/youtube-dl_31918/1234567890_Fake Video.mp4",
         "status": "finished",
         "total_bytes": 123456789,
     }]
     self.mock_valid_youtube_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=98765424.1,
         download_rate_unit=NetworkUnit("bit/s"),
         download_size=123456789,
         download_size_unit=StorageUnit("B"),
         elapsed_time=12.345678987654321,
         elapsed_time_unit=TimeUnit("s"),
         errors=[],
     )
     self.mock_extraction_fail_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-extractor",
                 description=YOUTUBE_ERRORS.get("youtube-extractor", ""),
                 traceback=
                 "Extraction failed!; please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.",
             )
         ],
     )
     self.mock_download_fail_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-download",
                 description=YOUTUBE_ERRORS.get("youtube-download", ""),
                 traceback="Download failed!",
             )
         ],
     )
     self.mock_missing_attribute_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-attribute",
                 description=YOUTUBE_ERRORS.get("youtube-attribute", ""),
                 traceback=str(self.mock_progress_dicts_missing_attribute),
             )
         ],
     )
     self.mock_final_only_result = (YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-progress_length",
                 description=YOUTUBE_ERRORS.get("youtube-progress_length",
                                                ""),
                 traceback=str(self.mock_progress_dicts_only_final),
             )
         ],
     ), )
     self.mock_final_only_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-progress_length",
                 description=YOUTUBE_ERRORS.get("youtube-progress_length",
                                                ""),
                 traceback=str(self.mock_progress_dicts_only_final),
             )
         ],
     )
     self.mock_file_remove_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-file",
                 description=YOUTUBE_ERRORS.get("youtube-file", ""),
                 traceback=
                 "[Errno 2] No such file or directory: 'example_file'",
             )
         ],
     )
     self.mock_directory_remove_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-no_directory",
                 description=YOUTUBE_ERRORS.get("youtube-no_directory", ""),
                 traceback=
                 "[Errno 2] No such file or directory: 'example_dir'",
             )
         ],
     )
     self.mock_directory_remove_nonempty_result = YouTubeMeasurementResult(
         id=self.id,
         url=self.test_url,
         download_rate=None,
         download_rate_unit=None,
         download_size=None,
         download_size_unit=None,
         elapsed_time=None,
         elapsed_time_unit=None,
         errors=[
             Error(
                 key="youtube-directory_nonempty",
                 description=YOUTUBE_ERRORS.get(
                     "youtube-directory_nonempty", ""),
                 traceback="[Errno 39] Directory not empty: 'example_dir'",
             )
         ],
     )