File: test_cpu.py

package info (click to toggle)
python-plyer 2.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,808 kB
  • sloc: python: 13,395; sh: 217; makefile: 177
file content (262 lines) | stat: -rw-r--r-- 7,532 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
'''
TestCPU
=======

Tested platforms:

* Windows
* Linux - nproc
'''

import unittest
from os import environ
from os.path import join
from unittest.mock import patch, Mock
from textwrap import dedent

from plyer.tests.common import PlatformTest, platform_import, splitpath


class MockedKernelCPU:
    def __init__(self, *args, **kwargs):
        self.fname = args[0] if args else ''
        self.cpu_path = join('/sys', 'devices', 'system', 'cpu')
        self.cores = 16
        self.indicies = 4

    def __enter__(self, *args):
        file_value = None
        cpu_path = self.cpu_path
        spath = splitpath(self.fname)

        if self.fname == join(cpu_path, 'present'):
            file_value = Mock()
            file_value.read.return_value = self.present
        elif spath[5] == 'cache' and spath[7] == 'level':
            file_value = Mock()
            # force bytes, because reading files as bytes
            file_value.read.return_value = str(
                self.index_types[spath[4]][spath[6]][spath[7]]
            ).encode('utf-8')
        return file_value

    def __exit__(self, *args):
        pass

    @property
    def present(self):
        rng = list(range(self.cores))
        start = str(rng[0])
        end = str(rng[-1])
        if start == end:  # cores == 1 --> b'0'
            value = str(start)
        else:  # cores > 1 --> b'0-n'
            value = str('-'.join([start, end]))
        return value.encode('utf-8')

    @property
    def listdir(self):
        return ['index{}'.format(i) for i in range(self.indicies)]

    @property
    def index_types(self):
        # assign L1 to index0-1, L2 to 2, L3 to 3
        types = {0: 1, 1: 1, 2: 2, 3: 3}

        return {
            'cpu{}'.format(c): {
                'index{}'.format(i): {
                    'level': types[i]
                }
                for i in range(self.indicies)
            }
            for c in range(self.cores)
        }


class MockedNProc:
    '''
    Mocked object used instead of 'nproc' binary in the Linux specific API
    plyer.platforms.linux.cpu. The same output structure is tested for
    the range of <min_version, max_version>.

    .. note:: Extend the object with another data sample if it does not match.
    '''

    min_version = '8.21'
    max_version = '8.21'
    logical_cores = 99

    def __init__(self, *args, **kwargs):
        # only to ignore all args, kwargs
        pass

    @staticmethod
    def communicate():
        '''
        Mock Popen.communicate, so that 'nproc' isn't used.
        '''
        return (str(MockedNProc.logical_cores).encode('utf-8'), )

    @staticmethod
    def whereis_exe(binary):
        '''
        Mock whereis_exe, so that it looks like
        Linux NProc binary is present on the system.
        '''
        return binary == 'nproc'

    @staticmethod
    def logical():
        '''
        Return percentage from mocked data.
        '''
        return int(MockedNProc.logical_cores)


class MockedProcinfo:
    # docs:
    # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    # /tree/arch/x86/kernel/cpu/proc.c
    sockets = 1  # physical id
    physical = 2  # core id
    threads_per_core = 2  # Intel specs document for i7-4500U
    logical = physical * threads_per_core  # processor

    def __init__(self, *args, **kwargs):
        self.fname = args[0] if args else ''

        self.output = []
        __step = 0  # 0,1,0,1 -> 0,0,1,1
        for soc in range(self.sockets):
            for log in range(self.logical):
                if log != 0 and not log % self.physical:
                    __step += 1
                self.output.append((dedent(
                    '''\
                    processor\t: {logical}
                    vendor_id\t: GenuineIntel
                    cpu family\t: 6
                    model\t\t: 69
                    model name\t: Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz
                    stepping\t: 1
                    microcode\t: 0x17
                    cpu MHz\t\t: 774.000
                    cache size\t: 4096 KB
                    physical id\t: {socket}
                    siblings\t: 4
                    core id\t\t: {physical}
                    cpu cores\t: {threads_per_core}
                    apicid\t\t: {logical}
                    initial apicid\t: 0
                    fpu\t\t: yes
                    fpu_exception\t: yes
                    cpuid level\t: 13
                    wp\t\t: yes
                    flags\t\t: fpu vme de pse tsc msr pae mce cx8 ...
                    bogomips\t: 3591.40
                    clflush size\t: 64
                    cache_alignment\t: 64
                    address sizes\t: 39 bits physical, 48 bits virtual
                    power management:
                    \n'''
                )).format(**{
                    'socket': soc,
                    'physical': __step,
                    'logical': log,
                    'threads_per_core': self.threads_per_core
                }))
        self.output = ''.join(self.output).encode('utf-8')

    def __enter__(self, *args):
        file_value = None

        if self.fname == '/proc/cpuinfo':
            file_value = Mock()
            file_value.readlines.return_value = self.output.split(
                '\n'.encode('utf-8')
            )
        return file_value

    def __exit__(self, *args):
        pass


class TestCPU(unittest.TestCase):
    '''
    TestCase for plyer.cpu.
    '''

    def test_cpu_linux_physical(self):
        cpu = platform_import(
            platform='linux',
            module_name='cpu',
            whereis_exe=lambda b: b == 'nproc'
        ).instance()

        stub = MockedProcinfo
        target = 'builtins.open'

        with patch(target=target, new=stub):
            sb = stub()
            self.assertEqual(
                cpu.physical, sb.physical
            )

    def test_cpu_linux_logical(self):
        '''
        Test mocked Linux NProc for plyer.cpu.
        '''
        cpu = platform_import(
            platform='linux',
            module_name='cpu',
            whereis_exe=MockedNProc.whereis_exe
        )
        cpu.Popen = MockedNProc
        cpu = cpu.instance()

        self.assertEqual(
            cpu.logical, MockedNProc.logical()
        )

    @PlatformTest('linux')
    def test_cpu_linux_cache(self):
        cpu = platform_import(
            platform='linux',
            module_name='cpu',
            whereis_exe=lambda b: b == 'nproc'
        ).instance()

        stub = MockedKernelCPU
        target = 'builtins.open'
        sub_target = 'plyer.platforms.linux.cpu.listdir'

        with patch(target=target, new=stub):
            with patch(target=sub_target, return_value=stub().listdir):
                sb = stub()
                self.assertEqual(
                    cpu.cache, {
                        'L1': sb.cores * 2,
                        'L2': sb.cores,
                        'L3': sb.cores
                    }
                )

    @PlatformTest('win')
    def test_cpu_win_logical(self):
        cpu = platform_import(
            platform='win',
            module_name='cpu'
        )

        cpu = cpu.instance()
        self.assertEqual(
            cpu.logical,
            # https://docs.microsoft.com/en-us/previous-versions/
            # windows/it-pro/windows-xp/bb490954(v=technet.10)
            int(environ['NUMBER_OF_PROCESSORS'])
        )


if __name__ == '__main__':
    unittest.main()