1# Copyright 2017 The Chromium OS 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"""Shared constants and methods for result utilities."""
6
7import collections
8import logging
9import math
10
11
12# Logging method, default to logging.debug. TKO parser use a different logger,
13# so it can overwrite the logging method here.
14LOG = logging.debug
15
16# Following are key names for directory summaries. The keys are started with /
17# so it can be differentiated with a valid file name. The short keys are
18# designed for smaller file size of the directory summary.
19
20# Original size of the directory or file
21ORIGINAL_SIZE_BYTES = '/S'
22# Size of the directory or file after trimming
23TRIMMED_SIZE_BYTES = '/T'
24# Size of the directory or file being collected from client side
25COLLECTED_SIZE_BYTES = '/C'
26# A dictionary of sub-directories' summary: name: {directory_summary}
27DIRS = '/D'
28# Default root directory name. To allow summaries to be merged effectively, all
29# summaries are collected with root directory of ''
30ROOT_DIR = ''
31
32# Information of test result sizes to be stored in tko_job_keyvals.
33# The total size (in kB) of test results that generated during the test,
34# including:
35#  * server side test logs and result files.
36#  * client side test logs, sysinfo, system logs and crash dumps.
37# Note that a test can collect the same test result files from DUT multiple
38# times during the test, before and after each iteration/test. So the value of
39# client_result_collected_KB could be larger than the value of
40# result_uploaded_KB, which is the size of result directory on the server side,
41# even if the test result throttling is not applied.
42#
43# Attributes of the named tuple includes:
44# client_result_collected_KB: The total size (in KB) of test results collected
45#         from test device.
46# original_result_total_KB: The original size (in KB) of test results before
47#         being trimmed.
48# result_uploaded_KB: The total size (in KB) of test results to be uploaded by
49#         gs_offloader.
50# result_throttled: Flag to indicate if test results collection is throttled.
51ResultSizeInfo = collections.namedtuple(
52        'ResultSizeInfo',
53        ['client_result_collected_KB',
54         'original_result_total_KB',
55         'result_uploaded_KB',
56         'result_throttled'])
57
58
59class NotEnoughDiskError(Exception):
60    """Exception to raise when the target directory doesn't have enough free
61    disk space.
62    """
63
64
65def get_result_size_info(client_collected_bytes, summary):
66    """Get the result size information.
67
68    @param client_collected_bytes: Size in bytes of results collected from the
69            test device.
70    @param summary: A dictionary of directory summary.
71    @return: A namedtuple of result size informations, including:
72            client_result_collected_KB: The total size (in KB) of test results
73                    collected from test device.
74            original_result_total_KB: The original size (in KB) of test results
75                    before being trimmed.
76            result_uploaded_KB: The total size (in KB) of test results to be
77                    uploaded.
78            result_throttled: True if test results collection is throttled.
79    """
80    client_result_collected_KB= client_collected_bytes / 1024
81    original_result_total_KB = summary.original_size / 1024
82    result_uploaded_KB = summary.trimmed_size / 1024
83    # Test results are considered to be throttled if the total size of
84    # results collected is different from the total size of trimmed results
85    # from the client side.
86    result_throttled = (summary.original_size > summary.trimmed_size)
87
88    return ResultSizeInfo(client_result_collected_KB=client_result_collected_KB,
89                          original_result_total_KB=original_result_total_KB,
90                          result_uploaded_KB=result_uploaded_KB,
91                          result_throttled=result_throttled)
92
93
94def get_size_string(size_bytes):
95    """Get a string of the given bytes.
96
97    Convert the number of bytes to the closest integer of file size measure,
98    i.e., KB, MB etc. If the size is less than 10, round to one decimal place of
99    the size value.
100
101    @param size_bytes: Number of bytes.
102    @return: A string representing `size_bytes` in KB, MB etc.
103    """
104    if size_bytes == 0:
105        return '0 B'
106    size_name = ('B', 'KB', 'MB', 'GB', 'TB', 'PB')
107    i = int(math.log(size_bytes, 1024))
108    p = math.pow(1024, i)
109    s = size_bytes / p
110    if s >= 10:
111        return '%d %s' % (int(s), size_name[i])
112    else:
113        # Round to one decimal place if the size is less than 10.
114        return '%0.1f %s' % (s, size_name[i])