Merge lp:~alisonken1/openlp/pjlink2-p into lp:openlp
- pjlink2-p
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 2813 |
Proposed branch: | lp:~alisonken1/openlp/pjlink2-p |
Merge into: | lp:openlp |
Diff against target: |
852 lines (+595/-40) 10 files modified
openlp/core/api/tab.py (+7/-11) openlp/core/common/__init__.py (+39/-0) openlp/core/projectors/manager.py (+2/-5) openlp/core/projectors/pjlink.py (+143/-18) tests/functional/openlp_core/api/test_tab.py (+11/-0) tests/openlp_core/__init__.py (+26/-0) tests/openlp_core/projectors/__init__.py (+1/-1) tests/openlp_core/projectors/test_projector_pjlink_udp.py (+360/-0) tests/openlp_core/projectors/test_projectorsourceform.py (+0/-2) tests/resources/projector/data.py (+6/-3) |
To merge this branch: | bzr merge lp:~alisonken1/openlp/pjlink2-p |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tomas Groth | Approve | ||
Tim Bentley | Approve | ||
Raoul Snyman | Pending | ||
Review via email: mp+337519@code.launchpad.net |
This proposal supersedes a proposal from 2018-02-11.
Commit message
PJLink2 Update P
Description of the change
- manager: Remove unused signal disconnect projectorNetwor
- Change PJLinkUDP.
- Add test_projector_
- Add test_projector_
- Add test_projector_
- Add test_projector_
- Add PJLinkUDP.
- Add PJLinkUDP.
- Add PJLinkUDP.
- Add PJLinkUDP.
- Move projector tests to tests/openlp_
- Update resources.
- Added dictionary of IP interfaces/
- Refactor tab.ApiTab.
- Fix tests for api.tab.
- Move dictionary of IP interfaces to function
-------
lp:~alisonken1/openlp/pjlink2-p (revision 2811)
https:/
https:/
https:/
Passed local tests so not sure what happened now
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Ken Roberts (alisonken1) wrote : Posted in a previous version of this proposal | # |
>> === modified file 'openlp/.version'
>> --- openlp/.version 2016-12-12 22:16:23 +0000
>> +++ openlp/.version 2018-02-10 09:09:49 +0000
>> @@ -1 +1 @@
>> -2.5.0
>> +2.5-bzr2809
>
> why?
huh?
Didn't know that happened. Must have been when I was twiddling with
pip install trying something out.
Reverted
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Looks ok and a good refactor.
Not 100% sure about the inline code for the Network lookup.
Let TGC or Superfly comment on that.
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Just the one request, everything else looks spiffy.
Tim Bentley (trb143) : | # |
Tomas Groth (tomasgroth) : | # |
Preview Diff
1 | === modified file 'openlp/core/api/tab.py' | |||
2 | --- openlp/core/api/tab.py 2017-12-29 09:15:48 +0000 | |||
3 | +++ openlp/core/api/tab.py 2018-02-12 01:05:51 +0000 | |||
4 | @@ -24,6 +24,7 @@ | |||
5 | 24 | """ | 24 | """ |
6 | 25 | from PyQt5 import QtCore, QtGui, QtNetwork, QtWidgets | 25 | from PyQt5 import QtCore, QtGui, QtNetwork, QtWidgets |
7 | 26 | 26 | ||
8 | 27 | from openlp.core.common import get_local_ip4 | ||
9 | 27 | from openlp.core.common.i18n import UiStrings, translate | 28 | from openlp.core.common.i18n import UiStrings, translate |
10 | 28 | from openlp.core.common.registry import Registry | 29 | from openlp.core.common.registry import Registry |
11 | 29 | from openlp.core.common.settings import Settings | 30 | from openlp.core.common.settings import Settings |
12 | @@ -219,17 +220,12 @@ | |||
13 | 219 | else: return ip_address | 220 | else: return ip_address |
14 | 220 | """ | 221 | """ |
15 | 221 | if ip_address == ZERO_URL: | 222 | if ip_address == ZERO_URL: |
27 | 222 | interfaces = QtNetwork.QNetworkInterface.allInterfaces() | 223 | # In case we have more than one interface |
28 | 223 | for interface in interfaces: | 224 | ifaces = get_local_ip4() |
29 | 224 | if not interface.isValid(): | 225 | for key in iter(ifaces): |
30 | 225 | continue | 226 | ip_address = ifaces.get(key)['ip'] |
31 | 226 | if not (interface.flags() & (QtNetwork.QNetworkInterface.IsUp | QtNetwork.QNetworkInterface.IsRunning)): | 227 | # We only want the first interface returned |
32 | 227 | continue | 228 | break |
22 | 228 | for address in interface.addressEntries(): | ||
23 | 229 | ip = address.ip() | ||
24 | 230 | if ip.protocol() == QtNetwork.QAbstractSocket.IPv4Protocol and \ | ||
25 | 231 | ip != QtNetwork.QHostAddress.LocalHost: | ||
26 | 232 | return ip.toString() | ||
33 | 233 | return ip_address | 229 | return ip_address |
34 | 234 | 230 | ||
35 | 235 | def load(self): | 231 | def load(self): |
36 | 236 | 232 | ||
37 | === modified file 'openlp/core/common/__init__.py' | |||
38 | --- openlp/core/common/__init__.py 2017-12-29 09:15:48 +0000 | |||
39 | +++ openlp/core/common/__init__.py 2018-02-12 01:05:51 +0000 | |||
40 | @@ -36,6 +36,7 @@ | |||
41 | 36 | 36 | ||
42 | 37 | from PyQt5 import QtGui | 37 | from PyQt5 import QtGui |
43 | 38 | from PyQt5.QtCore import QCryptographicHash as QHash | 38 | from PyQt5.QtCore import QCryptographicHash as QHash |
44 | 39 | from PyQt5.QtNetwork import QAbstractSocket, QHostAddress, QNetworkInterface | ||
45 | 39 | from chardet.universaldetector import UniversalDetector | 40 | from chardet.universaldetector import UniversalDetector |
46 | 40 | 41 | ||
47 | 41 | log = logging.getLogger(__name__ + '.__init__') | 42 | log = logging.getLogger(__name__ + '.__init__') |
48 | @@ -52,6 +53,44 @@ | |||
49 | 52 | WHITESPACE_REGEX = re.compile(r'[ \t]+') | 53 | WHITESPACE_REGEX = re.compile(r'[ \t]+') |
50 | 53 | 54 | ||
51 | 54 | 55 | ||
52 | 56 | def get_local_ip4(): | ||
53 | 57 | """ | ||
54 | 58 | Creates a dictionary of local IPv4 interfaces on local machine. | ||
55 | 59 | If no active interfaces available, returns a dict of localhost IPv4 information | ||
56 | 60 | |||
57 | 61 | :returns: Dict of interfaces | ||
58 | 62 | """ | ||
59 | 63 | # Get the local IPv4 active address(es) that are NOT localhost (lo or '127.0.0.1') | ||
60 | 64 | log.debug('Getting local IPv4 interface(es) information') | ||
61 | 65 | MY_IP4 = {} | ||
62 | 66 | for iface in QNetworkInterface.allInterfaces(): | ||
63 | 67 | if not iface.isValid() or not (iface.flags() & (QNetworkInterface.IsUp | QNetworkInterface.IsRunning)): | ||
64 | 68 | continue | ||
65 | 69 | for address in iface.addressEntries(): | ||
66 | 70 | ip = address.ip() | ||
67 | 71 | # NOTE: Next line will skip if interface is localhost - keep for now until we decide about it later | ||
68 | 72 | # if (ip.protocol() == QAbstractSocket.IPv4Protocol) and (ip != QHostAddress.LocalHost): | ||
69 | 73 | if (ip.protocol() == QAbstractSocket.IPv4Protocol): | ||
70 | 74 | MY_IP4[iface.name()] = {'ip': ip.toString(), | ||
71 | 75 | 'broadcast': address.broadcast().toString(), | ||
72 | 76 | 'netmask': address.netmask().toString(), | ||
73 | 77 | 'prefix': address.prefixLength(), | ||
74 | 78 | 'localnet': QHostAddress(address.netmask().toIPv4Address() & | ||
75 | 79 | ip.toIPv4Address()).toString() | ||
76 | 80 | } | ||
77 | 81 | log.debug('Adding {iface} to active list'.format(iface=iface.name())) | ||
78 | 82 | if len(MY_IP4) == 1: | ||
79 | 83 | if 'lo' in MY_IP4: | ||
80 | 84 | # No active interfaces - so leave localhost in there | ||
81 | 85 | log.warning('No active IPv4 interfaces found except localhost') | ||
82 | 86 | else: | ||
83 | 87 | # Since we have a valid IP4 interface, remove localhost | ||
84 | 88 | log.debug('Found at least one IPv4 interface, removing localhost') | ||
85 | 89 | MY_IP4.pop('lo') | ||
86 | 90 | |||
87 | 91 | return MY_IP4 | ||
88 | 92 | |||
89 | 93 | |||
90 | 55 | def trace_error_handler(logger): | 94 | def trace_error_handler(logger): |
91 | 56 | """ | 95 | """ |
92 | 57 | Log the calling path of an exception | 96 | Log the calling path of an exception |
93 | 58 | 97 | ||
94 | === modified file 'openlp/core/projectors/manager.py' | |||
95 | --- openlp/core/projectors/manager.py 2018-01-13 05:41:42 +0000 | |||
96 | +++ openlp/core/projectors/manager.py 2018-02-12 01:05:51 +0000 | |||
97 | @@ -308,7 +308,6 @@ | |||
98 | 308 | self.settings_section = 'projector' | 308 | self.settings_section = 'projector' |
99 | 309 | self.projectordb = projectordb | 309 | self.projectordb = projectordb |
100 | 310 | self.projector_list = [] | 310 | self.projector_list = [] |
101 | 311 | self.pjlink_udp = PJLinkUDP(self.projector_list) | ||
102 | 312 | self.source_select_form = None | 311 | self.source_select_form = None |
103 | 313 | 312 | ||
104 | 314 | def bootstrap_initialise(self): | 313 | def bootstrap_initialise(self): |
105 | @@ -323,6 +322,7 @@ | |||
106 | 323 | else: | 322 | else: |
107 | 324 | log.debug('Using existing ProjectorDB() instance') | 323 | log.debug('Using existing ProjectorDB() instance') |
108 | 325 | self.get_settings() | 324 | self.get_settings() |
109 | 325 | self.pjlink_udp = PJLinkUDP(self.projector_list) | ||
110 | 326 | 326 | ||
111 | 327 | def bootstrap_post_set_up(self): | 327 | def bootstrap_post_set_up(self): |
112 | 328 | """ | 328 | """ |
113 | @@ -344,6 +344,7 @@ | |||
114 | 344 | """ | 344 | """ |
115 | 345 | Retrieve the saved settings | 345 | Retrieve the saved settings |
116 | 346 | """ | 346 | """ |
117 | 347 | log.debug('Updating ProjectorManager settings') | ||
118 | 347 | settings = Settings() | 348 | settings = Settings() |
119 | 348 | settings.beginGroup(self.settings_section) | 349 | settings.beginGroup(self.settings_section) |
120 | 349 | self.autostart = settings.value('connect on start') | 350 | self.autostart = settings.value('connect on start') |
121 | @@ -502,10 +503,6 @@ | |||
122 | 502 | if ans == msg.Cancel: | 503 | if ans == msg.Cancel: |
123 | 503 | return | 504 | return |
124 | 504 | try: | 505 | try: |
125 | 505 | projector.link.projectorNetwork.disconnect(self.update_status) | ||
126 | 506 | except (AttributeError, TypeError): | ||
127 | 507 | pass | ||
128 | 508 | try: | ||
129 | 509 | projector.link.changeStatus.disconnect(self.update_status) | 506 | projector.link.changeStatus.disconnect(self.update_status) |
130 | 510 | except (AttributeError, TypeError): | 507 | except (AttributeError, TypeError): |
131 | 511 | pass | 508 | pass |
132 | 512 | 509 | ||
133 | === modified file 'openlp/core/projectors/pjlink.py' | |||
134 | --- openlp/core/projectors/pjlink.py 2018-01-13 05:41:42 +0000 | |||
135 | +++ openlp/core/projectors/pjlink.py 2018-02-12 01:05:51 +0000 | |||
136 | @@ -64,7 +64,7 @@ | |||
137 | 64 | log = logging.getLogger(__name__) | 64 | log = logging.getLogger(__name__) |
138 | 65 | log.debug('pjlink loaded') | 65 | log.debug('pjlink loaded') |
139 | 66 | 66 | ||
141 | 67 | __all__ = ['PJLink'] | 67 | __all__ = ['PJLink', 'PJLinkUDP'] |
142 | 68 | 68 | ||
143 | 69 | # Shortcuts | 69 | # Shortcuts |
144 | 70 | SocketError = QtNetwork.QAbstractSocket.SocketError | 70 | SocketError = QtNetwork.QAbstractSocket.SocketError |
145 | @@ -79,22 +79,145 @@ | |||
146 | 79 | """ | 79 | """ |
147 | 80 | Socket service for PJLink UDP socket. | 80 | Socket service for PJLink UDP socket. |
148 | 81 | """ | 81 | """ |
149 | 82 | # New commands available in PJLink Class 2 | ||
150 | 83 | pjlink_udp_commands = [ | ||
151 | 84 | 'ACKN', # Class 2 (cmd is SRCH) | ||
152 | 85 | 'ERST', # Class 1/2 | ||
153 | 86 | 'INPT', # Class 1/2 | ||
154 | 87 | 'LKUP', # Class 2 (reply only - no cmd) | ||
155 | 88 | 'POWR', # Class 1/2 | ||
156 | 89 | 'SRCH' # Class 2 (reply is ACKN) | ||
157 | 90 | ] | ||
158 | 91 | |||
159 | 92 | def __init__(self, projector_list, port=PJLINK_PORT): | 82 | def __init__(self, projector_list, port=PJLINK_PORT): |
160 | 93 | """ | 83 | """ |
162 | 94 | Initialize socket | 84 | Socket services for PJLink UDP packets. |
163 | 85 | |||
164 | 86 | Since all UDP packets from any projector will come into the same | ||
165 | 87 | port, process UDP packets here then route to the appropriate | ||
166 | 88 | projector instance as needed. | ||
167 | 95 | """ | 89 | """ |
168 | 90 | # Keep track of currently defined projectors so we can route | ||
169 | 91 | # inbound packets to the correct instance | ||
170 | 92 | super().__init__() | ||
171 | 96 | self.projector_list = projector_list | 93 | self.projector_list = projector_list |
172 | 97 | self.port = port | 94 | self.port = port |
173 | 95 | # Local defines | ||
174 | 96 | self.ackn_list = {} # Replies from online projetors | ||
175 | 97 | self.search_active = False | ||
176 | 98 | self.search_time = 30000 # 30 seconds for allowed time | ||
177 | 99 | self.search_timer = QtCore.QTimer() | ||
178 | 100 | # New commands available in PJLink Class 2 | ||
179 | 101 | # ACKN/SRCH is processed here since it's used to find available projectors | ||
180 | 102 | # Other commands are processed by the individual projector instances | ||
181 | 103 | self.pjlink_udp_functions = { | ||
182 | 104 | 'ACKN': self.process_ackn, # Class 2, command is 'SRCH' | ||
183 | 105 | 'ERST': None, # Class 1/2 | ||
184 | 106 | 'INPT': None, # Class 1/2 | ||
185 | 107 | 'LKUP': None, # Class 2 (reply only - no cmd) | ||
186 | 108 | 'POWR': None, # Class 1/2 | ||
187 | 109 | 'SRCH': self.process_srch # Class 2 (reply is ACKN) | ||
188 | 110 | } | ||
189 | 111 | |||
190 | 112 | self.readyRead.connect(self.get_datagram) | ||
191 | 113 | log.debug('(UDP) PJLinkUDP() Initialized') | ||
192 | 114 | |||
193 | 115 | @QtCore.pyqtSlot() | ||
194 | 116 | def get_datagram(self): | ||
195 | 117 | """ | ||
196 | 118 | Retrieve packet and basic checks | ||
197 | 119 | """ | ||
198 | 120 | log.debug('(UDP) get_datagram() - Receiving data') | ||
199 | 121 | read = self.pendingDatagramSize() | ||
200 | 122 | if read < 0: | ||
201 | 123 | log.warn('(UDP) No data (-1)') | ||
202 | 124 | return | ||
203 | 125 | if read < 1: | ||
204 | 126 | log.warn('(UDP) get_datagram() called when pending data size is 0') | ||
205 | 127 | return | ||
206 | 128 | data, peer_address, peer_port = self.readDatagram(self.pendingDatagramSize()) | ||
207 | 129 | log.debug('(UDP) {size} bytes received from {adx} on port {port}'.format(size=len(data), | ||
208 | 130 | adx=peer_address, | ||
209 | 131 | port=peer_port)) | ||
210 | 132 | log.debug('(UDP) packet "{data}"'.format(data=data)) | ||
211 | 133 | if len(data) < 0: | ||
212 | 134 | log.warn('(UDP) No data (-1)') | ||
213 | 135 | return | ||
214 | 136 | elif len(data) < 8: | ||
215 | 137 | # Minimum packet is '%2CCCC=' | ||
216 | 138 | log.warn('(UDP) Invalid packet - not enough data') | ||
217 | 139 | return | ||
218 | 140 | elif data is None: | ||
219 | 141 | log.warn('(UDP) No data (None)') | ||
220 | 142 | return | ||
221 | 143 | elif len(data) > PJLINK_MAX_PACKET: | ||
222 | 144 | log.warn('(UDP) Invalid packet - length too long') | ||
223 | 145 | return | ||
224 | 146 | elif not data.startswith(PJLINK_PREFIX): | ||
225 | 147 | log.warn('(UDP) Invalid packet - does not start with PJLINK_PREFIX') | ||
226 | 148 | return | ||
227 | 149 | elif data[1] != '2': | ||
228 | 150 | log.warn('(UDP) Invalid packet - missing/invalid PJLink class version') | ||
229 | 151 | return | ||
230 | 152 | elif data[6] != '=': | ||
231 | 153 | log.warn('(UDP) Invalid packet - separator missing') | ||
232 | 154 | return | ||
233 | 155 | # First two characters are header information we don't need at this time | ||
234 | 156 | cmd, data = data[2:].split('=') | ||
235 | 157 | if cmd not in self.pjlink_udp_functions: | ||
236 | 158 | log.warn('(UDP) Invalid packet - not a valid PJLink UDP reply') | ||
237 | 159 | return | ||
238 | 160 | if self.pjlink_udp_functions[cmd] is not None: | ||
239 | 161 | log.debug('(UDP) Processing {cmd} with "{data}"'.format(cmd=cmd, data=data)) | ||
240 | 162 | return self.pjlink_udp_functions[cmd](data=data, host=peer_address, port=peer_port) | ||
241 | 163 | else: | ||
242 | 164 | log.debug('(UDP) Checking projector list for ip {host} to process'.format(host=peer_address)) | ||
243 | 165 | for projector in self.projector_list: | ||
244 | 166 | if peer_address == projector.ip: | ||
245 | 167 | if cmd not in projector.pjlink_functions: | ||
246 | 168 | log.error('(UDP) Could not find method to process ' | ||
247 | 169 | '"{cmd}" in {host}'.format(cmd=cmd, host=projector.ip)) | ||
248 | 170 | return | ||
249 | 171 | log.debug('(UDP) Calling "{cmd}" in {host}'.format(cmd=cmd, host=projector.ip)) | ||
250 | 172 | return projector.pjlink_functions[cmd](data=data) | ||
251 | 173 | log.warn('(UDP) Could not find projector with ip {ip} to process packet'.format(ip=peer_address)) | ||
252 | 174 | return | ||
253 | 175 | |||
254 | 176 | def process_ackn(self, data, host, port): | ||
255 | 177 | """ | ||
256 | 178 | Process the ACKN command. | ||
257 | 179 | |||
258 | 180 | :param data: Data in packet | ||
259 | 181 | :param host: IP address of sending host | ||
260 | 182 | :param port: Port received on | ||
261 | 183 | """ | ||
262 | 184 | log.debug('(UDP) Processing ACKN packet') | ||
263 | 185 | if host not in self.ackn_list: | ||
264 | 186 | log.debug('(UDP) Adding {host} to ACKN list'.format(host=host)) | ||
265 | 187 | self.ackn_list[host] = {'data': data, | ||
266 | 188 | 'port': port} | ||
267 | 189 | else: | ||
268 | 190 | log.warn('(UDP) Host {host} already replied - ignoring'.format(host=host)) | ||
269 | 191 | |||
270 | 192 | def process_srch(self, data, host, port): | ||
271 | 193 | """ | ||
272 | 194 | Process the SRCH command. | ||
273 | 195 | |||
274 | 196 | SRCH is processed by terminals so we ignore any packet. | ||
275 | 197 | |||
276 | 198 | :param data: Data in packet | ||
277 | 199 | :param host: IP address of sending host | ||
278 | 200 | :param port: Port received on | ||
279 | 201 | """ | ||
280 | 202 | log.debug('(UDP) SRCH packet received - ignoring') | ||
281 | 203 | return | ||
282 | 204 | |||
283 | 205 | def search_start(self): | ||
284 | 206 | """ | ||
285 | 207 | Start search for projectors on local network | ||
286 | 208 | """ | ||
287 | 209 | self.search_active = True | ||
288 | 210 | self.ackn_list = {} | ||
289 | 211 | # TODO: Send SRCH packet here | ||
290 | 212 | self.search_timer.singleShot(self.search_time, self.search_stop) | ||
291 | 213 | |||
292 | 214 | @QtCore.pyqtSlot() | ||
293 | 215 | def search_stop(self): | ||
294 | 216 | """ | ||
295 | 217 | Stop search | ||
296 | 218 | """ | ||
297 | 219 | self.search_active = False | ||
298 | 220 | self.search_timer.stop() | ||
299 | 98 | 221 | ||
300 | 99 | 222 | ||
301 | 100 | class PJLinkCommands(object): | 223 | class PJLinkCommands(object): |
302 | @@ -257,8 +380,9 @@ | |||
303 | 257 | else: | 380 | else: |
304 | 258 | clss = data | 381 | clss = data |
305 | 259 | self.pjlink_class = clss | 382 | self.pjlink_class = clss |
308 | 260 | log.debug('({ip}) Setting pjlink_class for this projector to "{data}"'.format(ip=self.entry.name, | 383 | log.debug('({ip}) Setting pjlink_class for this projector ' |
309 | 261 | data=self.pjlink_class)) | 384 | 'to "{data}"'.format(ip=self.entry.name, |
310 | 385 | data=self.pjlink_class)) | ||
311 | 262 | # Since we call this one on first connect, setup polling from here | 386 | # Since we call this one on first connect, setup polling from here |
312 | 263 | if not self.no_poll: | 387 | if not self.no_poll: |
313 | 264 | log.debug('({ip}) process_pjlink(): Starting timer'.format(ip=self.entry.name)) | 388 | log.debug('({ip}) process_pjlink(): Starting timer'.format(ip=self.entry.name)) |
314 | @@ -276,9 +400,10 @@ | |||
315 | 276 | """ | 400 | """ |
316 | 277 | if len(data) != PJLINK_ERST_DATA['DATA_LENGTH']: | 401 | if len(data) != PJLINK_ERST_DATA['DATA_LENGTH']: |
317 | 278 | count = PJLINK_ERST_DATA['DATA_LENGTH'] | 402 | count = PJLINK_ERST_DATA['DATA_LENGTH'] |
321 | 279 | log.warning('({ip}) Invalid error status response "{data}": length != {count}'.format(ip=self.entry.name, | 403 | log.warning('({ip}) Invalid error status response "{data}": ' |
322 | 280 | data=data, | 404 | 'length != {count}'.format(ip=self.entry.name, |
323 | 281 | count=count)) | 405 | data=data, |
324 | 406 | count=count)) | ||
325 | 282 | return | 407 | return |
326 | 283 | try: | 408 | try: |
327 | 284 | datacheck = int(data) | 409 | datacheck = int(data) |
328 | @@ -557,7 +682,7 @@ | |||
329 | 557 | 682 | ||
330 | 558 | class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): | 683 | class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): |
331 | 559 | """ | 684 | """ |
333 | 560 | Socket service for PJLink TCP socket. | 685 | Socket services for PJLink TCP packets. |
334 | 561 | """ | 686 | """ |
335 | 562 | # Signals sent by this module | 687 | # Signals sent by this module |
336 | 563 | changeStatus = QtCore.pyqtSignal(str, int, str) | 688 | changeStatus = QtCore.pyqtSignal(str, int, str) |
337 | 564 | 689 | ||
338 | === modified file 'tests/functional/openlp_core/api/test_tab.py' | |||
339 | --- tests/functional/openlp_core/api/test_tab.py 2017-12-29 09:15:48 +0000 | |||
340 | +++ tests/functional/openlp_core/api/test_tab.py 2018-02-12 01:05:51 +0000 | |||
341 | @@ -29,6 +29,7 @@ | |||
342 | 29 | from PyQt5 import QtWidgets | 29 | from PyQt5 import QtWidgets |
343 | 30 | 30 | ||
344 | 31 | from openlp.core.api.tab import ApiTab | 31 | from openlp.core.api.tab import ApiTab |
345 | 32 | from openlp.core.common import get_local_ip4 | ||
346 | 32 | from openlp.core.common.registry import Registry | 33 | from openlp.core.common.registry import Registry |
347 | 33 | from openlp.core.common.settings import Settings | 34 | from openlp.core.common.settings import Settings |
348 | 34 | from tests.helpers.testmixin import TestMixin | 35 | from tests.helpers.testmixin import TestMixin |
349 | @@ -63,6 +64,7 @@ | |||
350 | 63 | Registry().create() | 64 | Registry().create() |
351 | 64 | Registry().set_flag('website_version', '00-00-0000') | 65 | Registry().set_flag('website_version', '00-00-0000') |
352 | 65 | self.form = ApiTab(self.parent) | 66 | self.form = ApiTab(self.parent) |
353 | 67 | self.my_ip4_list = get_local_ip4() | ||
354 | 66 | 68 | ||
355 | 67 | def tearDown(self): | 69 | def tearDown(self): |
356 | 68 | """ | 70 | """ |
357 | @@ -76,11 +78,18 @@ | |||
358 | 76 | """ | 78 | """ |
359 | 77 | Test the get_ip_address function with ZERO_URL | 79 | Test the get_ip_address function with ZERO_URL |
360 | 78 | """ | 80 | """ |
361 | 81 | # GIVEN: list of local IP addresses for this machine | ||
362 | 82 | ip4_list = [] | ||
363 | 83 | for ip4 in iter(self.my_ip4_list): | ||
364 | 84 | ip4_list.append(self.my_ip4_list.get(ip4)['ip']) | ||
365 | 85 | |||
366 | 79 | # WHEN: the default ip address is given | 86 | # WHEN: the default ip address is given |
367 | 80 | ip_address = self.form.get_ip_address(ZERO_URL) | 87 | ip_address = self.form.get_ip_address(ZERO_URL) |
368 | 88 | |||
369 | 81 | # THEN: the default ip address will be returned | 89 | # THEN: the default ip address will be returned |
370 | 82 | assert re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), \ | 90 | assert re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), \ |
371 | 83 | 'The return value should be a valid ip address' | 91 | 'The return value should be a valid ip address' |
372 | 92 | assert ip_address in ip4_list, 'The return address should be in the list of local IP addresses' | ||
373 | 84 | 93 | ||
374 | 85 | def test_get_ip_address_with_ip(self): | 94 | def test_get_ip_address_with_ip(self): |
375 | 86 | """ | 95 | """ |
376 | @@ -88,8 +97,10 @@ | |||
377 | 88 | """ | 97 | """ |
378 | 89 | # GIVEN: An ip address | 98 | # GIVEN: An ip address |
379 | 90 | given_ip = '192.168.1.1' | 99 | given_ip = '192.168.1.1' |
380 | 100 | |||
381 | 91 | # WHEN: the default ip address is given | 101 | # WHEN: the default ip address is given |
382 | 92 | ip_address = self.form.get_ip_address(given_ip) | 102 | ip_address = self.form.get_ip_address(given_ip) |
383 | 103 | |||
384 | 93 | # THEN: the default ip address will be returned | 104 | # THEN: the default ip address will be returned |
385 | 94 | assert ip_address == given_ip, 'The return value should be %s' % given_ip | 105 | assert ip_address == given_ip, 'The return value should be %s' % given_ip |
386 | 95 | 106 | ||
387 | 96 | 107 | ||
388 | === added directory 'tests/openlp_core' | |||
389 | === added file 'tests/openlp_core/__init__.py' | |||
390 | --- tests/openlp_core/__init__.py 1970-01-01 00:00:00 +0000 | |||
391 | +++ tests/openlp_core/__init__.py 2018-02-12 01:05:51 +0000 | |||
392 | @@ -0,0 +1,26 @@ | |||
393 | 1 | # -*- coding: utf-8 -*- | ||
394 | 2 | # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 | ||
395 | 3 | |||
396 | 4 | ############################################################################### | ||
397 | 5 | # OpenLP - Open Source Lyrics Projection # | ||
398 | 6 | # --------------------------------------------------------------------------- # | ||
399 | 7 | # Copyright (c) 2008-2018 OpenLP Developers # | ||
400 | 8 | # --------------------------------------------------------------------------- # | ||
401 | 9 | # This program is free software; you can redistribute it and/or modify it # | ||
402 | 10 | # under the terms of the GNU General Public License as published by the Free # | ||
403 | 11 | # Software Foundation; version 2 of the License. # | ||
404 | 12 | # # | ||
405 | 13 | # This program is distributed in the hope that it will be useful, but WITHOUT # | ||
406 | 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # | ||
407 | 15 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # | ||
408 | 16 | # more details. # | ||
409 | 17 | # # | ||
410 | 18 | # You should have received a copy of the GNU General Public License along # | ||
411 | 19 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | ||
412 | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | ||
413 | 21 | ############################################################################### | ||
414 | 22 | """ | ||
415 | 23 | :mod: `tests.openlp_core` module | ||
416 | 24 | |||
417 | 25 | Tests modules/files for module openlp.core | ||
418 | 26 | """ | ||
419 | 0 | 27 | ||
420 | === renamed directory 'tests/functional/openlp_core/projectors' => 'tests/openlp_core/projectors' | |||
421 | === modified file 'tests/openlp_core/projectors/__init__.py' | |||
422 | --- tests/functional/openlp_core/projectors/__init__.py 2017-11-10 11:59:38 +0000 | |||
423 | +++ tests/openlp_core/projectors/__init__.py 2018-02-12 01:05:51 +0000 | |||
424 | @@ -20,5 +20,5 @@ | |||
425 | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | 20 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
426 | 21 | ############################################################################### | 21 | ############################################################################### |
427 | 22 | """ | 22 | """ |
429 | 23 | Module-level functions for the functional test suite | 23 | Module-level functions for the projector test suite |
430 | 24 | """ | 24 | """ |
431 | 25 | 25 | ||
432 | === added file 'tests/openlp_core/projectors/test_projector_pjlink_udp.py' | |||
433 | --- tests/openlp_core/projectors/test_projector_pjlink_udp.py 1970-01-01 00:00:00 +0000 | |||
434 | +++ tests/openlp_core/projectors/test_projector_pjlink_udp.py 2018-02-12 01:05:51 +0000 | |||
435 | @@ -0,0 +1,360 @@ | |||
436 | 1 | |||
437 | 2 | # -*- coding: utf-8 -*- | ||
438 | 3 | # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 | ||
439 | 4 | |||
440 | 5 | ############################################################################### | ||
441 | 6 | # OpenLP - Open Source Lyrics Projection # | ||
442 | 7 | # --------------------------------------------------------------------------- # | ||
443 | 8 | # Copyright (c) 2008-2018 OpenLP Developers # | ||
444 | 9 | # --------------------------------------------------------------------------- # | ||
445 | 10 | # This program is free software; you can redistribute it and/or modify it # | ||
446 | 11 | # under the terms of the GNU General Public License as published by the Free # | ||
447 | 12 | # Software Foundation; version 2 of the License. # | ||
448 | 13 | # # | ||
449 | 14 | # This program is distributed in the hope that it will be useful, but WITHOUT # | ||
450 | 15 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # | ||
451 | 16 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # | ||
452 | 17 | # more details. # | ||
453 | 18 | # # | ||
454 | 19 | # You should have received a copy of the GNU General Public License along # | ||
455 | 20 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # | ||
456 | 21 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # | ||
457 | 22 | ############################################################################### | ||
458 | 23 | """ | ||
459 | 24 | Package to test the PJLink UDP functions | ||
460 | 25 | """ | ||
461 | 26 | |||
462 | 27 | from unittest import TestCase | ||
463 | 28 | from unittest.mock import call, patch | ||
464 | 29 | |||
465 | 30 | import openlp.core.projectors.pjlink | ||
466 | 31 | from openlp.core.projectors.constants import PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_PREFIX | ||
467 | 32 | |||
468 | 33 | from openlp.core.projectors.db import Projector | ||
469 | 34 | from openlp.core.projectors.pjlink import PJLinkUDP | ||
470 | 35 | from tests.resources.projector.data import TEST1_DATA, TEST2_DATA | ||
471 | 36 | |||
472 | 37 | |||
473 | 38 | class TestPJLinkBase(TestCase): | ||
474 | 39 | """ | ||
475 | 40 | Tests for the PJLinkUDP class | ||
476 | 41 | """ | ||
477 | 42 | def setUp(self): | ||
478 | 43 | """ | ||
479 | 44 | Setup generic test conditions | ||
480 | 45 | """ | ||
481 | 46 | self.test_list = [Projector(**TEST1_DATA), Projector(**TEST2_DATA)] | ||
482 | 47 | |||
483 | 48 | def tearDown(self): | ||
484 | 49 | """ | ||
485 | 50 | Close generic test condidtions | ||
486 | 51 | """ | ||
487 | 52 | self.test_list = None | ||
488 | 53 | |||
489 | 54 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
490 | 55 | def test_get_datagram_data_invalid_class(self, mock_log): | ||
491 | 56 | """ | ||
492 | 57 | Test get_datagram with invalid class number | ||
493 | 58 | """ | ||
494 | 59 | # GIVEN: Test setup | ||
495 | 60 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
496 | 61 | log_warn_calls = [call('(UDP) Invalid packet - missing/invalid PJLink class version')] | ||
497 | 62 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
498 | 63 | call('(UDP) get_datagram() - Receiving data'), | ||
499 | 64 | call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), | ||
500 | 65 | call('(UDP) packet "%1ACKN=11:11:11:11:11:11"')] | ||
501 | 66 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
502 | 67 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
503 | 68 | mock_datagram.return_value = 24 | ||
504 | 69 | mock_read.return_value = ('{prefix}1ACKN={mac}'.format(prefix=PJLINK_PREFIX, mac=TEST1_DATA['mac_adx']), | ||
505 | 70 | TEST1_DATA['ip'], PJLINK_PORT) | ||
506 | 71 | |||
507 | 72 | # WHEN: get_datagram called with 0 bytes ready | ||
508 | 73 | pjlink_udp.get_datagram() | ||
509 | 74 | |||
510 | 75 | # THEN: Log entries should be made and method returns | ||
511 | 76 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
512 | 77 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
513 | 78 | |||
514 | 79 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
515 | 80 | def test_get_datagram_data_invalid_command(self, mock_log): | ||
516 | 81 | """ | ||
517 | 82 | Test get_datagram with invalid PJLink UDP command | ||
518 | 83 | """ | ||
519 | 84 | # GIVEN: Test setup | ||
520 | 85 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
521 | 86 | log_warn_calls = [call('(UDP) Invalid packet - not a valid PJLink UDP reply')] | ||
522 | 87 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
523 | 88 | call('(UDP) get_datagram() - Receiving data'), | ||
524 | 89 | call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), | ||
525 | 90 | call('(UDP) packet "%2DUMB=11:11:11:11:11:11"')] | ||
526 | 91 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
527 | 92 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
528 | 93 | mock_datagram.return_value = 24 | ||
529 | 94 | mock_read.return_value = ('{prefix}2DUMB={mac}'.format(prefix=PJLINK_PREFIX, mac=TEST1_DATA['mac_adx']), | ||
530 | 95 | TEST1_DATA['ip'], PJLINK_PORT) | ||
531 | 96 | |||
532 | 97 | # WHEN: get_datagram called with 0 bytes ready | ||
533 | 98 | pjlink_udp.get_datagram() | ||
534 | 99 | |||
535 | 100 | # THEN: Log entries should be made and method returns | ||
536 | 101 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
537 | 102 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
538 | 103 | |||
539 | 104 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
540 | 105 | def test_get_datagram_data_invalid_prefix(self, mock_log): | ||
541 | 106 | """ | ||
542 | 107 | Test get_datagram when prefix != PJLINK_PREFIX | ||
543 | 108 | """ | ||
544 | 109 | # GIVEN: Test setup | ||
545 | 110 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
546 | 111 | log_warn_calls = [call('(UDP) Invalid packet - does not start with PJLINK_PREFIX')] | ||
547 | 112 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
548 | 113 | call('(UDP) get_datagram() - Receiving data'), | ||
549 | 114 | call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), | ||
550 | 115 | call('(UDP) packet "$2ACKN=11:11:11:11:11:11"')] | ||
551 | 116 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
552 | 117 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
553 | 118 | mock_datagram.return_value = 24 | ||
554 | 119 | mock_read.return_value = ('{prefix}2ACKN={mac}'.format(prefix='$', mac=TEST1_DATA['mac_adx']), | ||
555 | 120 | TEST1_DATA['ip'], PJLINK_PORT) | ||
556 | 121 | |||
557 | 122 | # WHEN: get_datagram called with 0 bytes ready | ||
558 | 123 | pjlink_udp.get_datagram() | ||
559 | 124 | |||
560 | 125 | # THEN: Log entries should be made and method returns | ||
561 | 126 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
562 | 127 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
563 | 128 | |||
564 | 129 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
565 | 130 | def test_get_datagram_data_invalid_separator(self, mock_log): | ||
566 | 131 | """ | ||
567 | 132 | Test get_datagram when separator not equal to = | ||
568 | 133 | """ | ||
569 | 134 | # GIVEN: Test setup | ||
570 | 135 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
571 | 136 | log_warn_calls = [call('(UDP) Invalid packet - separator missing')] | ||
572 | 137 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
573 | 138 | call('(UDP) get_datagram() - Receiving data'), | ||
574 | 139 | call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), | ||
575 | 140 | call('(UDP) packet "%2ACKN 11:11:11:11:11:11"')] | ||
576 | 141 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
577 | 142 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
578 | 143 | mock_datagram.return_value = 24 | ||
579 | 144 | mock_read.return_value = ('{prefix}2ACKN {mac}'.format(prefix=PJLINK_PREFIX, mac=TEST1_DATA['mac_adx']), | ||
580 | 145 | TEST1_DATA['ip'], PJLINK_PORT) | ||
581 | 146 | |||
582 | 147 | # WHEN: get_datagram called with 0 bytes ready | ||
583 | 148 | pjlink_udp.get_datagram() | ||
584 | 149 | |||
585 | 150 | # THEN: Log entries should be made and method returns | ||
586 | 151 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
587 | 152 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
588 | 153 | |||
589 | 154 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
590 | 155 | def test_get_datagram_data_long(self, mock_log): | ||
591 | 156 | """ | ||
592 | 157 | Test get_datagram when datagram > PJLINK_MAX_PACKET | ||
593 | 158 | """ | ||
594 | 159 | # GIVEN: Test setup | ||
595 | 160 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
596 | 161 | log_warn_calls = [call('(UDP) Invalid packet - length too long')] | ||
597 | 162 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
598 | 163 | call('(UDP) get_datagram() - Receiving data'), | ||
599 | 164 | call('(UDP) 143 bytes received from 111.111.111.111 on port 4352'), | ||
600 | 165 | call('(UDP) packet "%2ACKN={long}"'.format(long='X' * PJLINK_MAX_PACKET))] | ||
601 | 166 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
602 | 167 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
603 | 168 | mock_datagram.return_value = PJLINK_MAX_PACKET + 7 | ||
604 | 169 | mock_read.return_value = ('{prefix}2ACKN={long}'.format(prefix=PJLINK_PREFIX, | ||
605 | 170 | long='X' * PJLINK_MAX_PACKET), | ||
606 | 171 | TEST1_DATA['ip'], PJLINK_PORT) | ||
607 | 172 | |||
608 | 173 | # WHEN: get_datagram called with 0 bytes ready | ||
609 | 174 | pjlink_udp.get_datagram() | ||
610 | 175 | |||
611 | 176 | # THEN: Log entries should be made and method returns | ||
612 | 177 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
613 | 178 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
614 | 179 | |||
615 | 180 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
616 | 181 | def test_get_datagram_data_negative_zero_length(self, mock_log): | ||
617 | 182 | """ | ||
618 | 183 | Test get_datagram when pendingDatagramSize = 0 | ||
619 | 184 | """ | ||
620 | 185 | # GIVEN: Test setup | ||
621 | 186 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
622 | 187 | log_warn_calls = [call('(UDP) No data (-1)')] | ||
623 | 188 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
624 | 189 | call('(UDP) get_datagram() - Receiving data')] | ||
625 | 190 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
626 | 191 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
627 | 192 | mock_datagram.return_value = -1 | ||
628 | 193 | mock_read.return_value = ('', TEST1_DATA['ip'], PJLINK_PORT) | ||
629 | 194 | |||
630 | 195 | # WHEN: get_datagram called with 0 bytes ready | ||
631 | 196 | pjlink_udp.get_datagram() | ||
632 | 197 | |||
633 | 198 | # THEN: Log entries should be made and method returns | ||
634 | 199 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
635 | 200 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
636 | 201 | |||
637 | 202 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
638 | 203 | def test_get_datagram_data_no_data(self, mock_log): | ||
639 | 204 | """ | ||
640 | 205 | Test get_datagram when data length = 0 | ||
641 | 206 | """ | ||
642 | 207 | # GIVEN: Test setup | ||
643 | 208 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
644 | 209 | log_warn_calls = [call('(UDP) Invalid packet - not enough data')] | ||
645 | 210 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
646 | 211 | call('(UDP) get_datagram() - Receiving data')] | ||
647 | 212 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
648 | 213 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
649 | 214 | mock_datagram.return_value = 1 | ||
650 | 215 | mock_read.return_value = ('', TEST1_DATA['ip'], PJLINK_PORT) | ||
651 | 216 | |||
652 | 217 | # WHEN: get_datagram called with 0 bytes ready | ||
653 | 218 | pjlink_udp.get_datagram() | ||
654 | 219 | |||
655 | 220 | # THEN: Log entries should be made and method returns | ||
656 | 221 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
657 | 222 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
658 | 223 | |||
659 | 224 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
660 | 225 | def test_get_datagram_data_short(self, mock_log): | ||
661 | 226 | """ | ||
662 | 227 | Test get_datagram when data length < 8 | ||
663 | 228 | """ | ||
664 | 229 | # GIVEN: Test setup | ||
665 | 230 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
666 | 231 | log_warn_calls = [call('(UDP) Invalid packet - not enough data')] | ||
667 | 232 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
668 | 233 | call('(UDP) get_datagram() - Receiving data')] | ||
669 | 234 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ | ||
670 | 235 | patch.object(pjlink_udp, 'readDatagram') as mock_read: | ||
671 | 236 | mock_datagram.return_value = 6 | ||
672 | 237 | mock_read.return_value = ('{prefix}2ACKN'.format(prefix=PJLINK_PREFIX), TEST1_DATA['ip'], PJLINK_PORT) | ||
673 | 238 | |||
674 | 239 | # WHEN: get_datagram called with 0 bytes ready | ||
675 | 240 | pjlink_udp.get_datagram() | ||
676 | 241 | |||
677 | 242 | # THEN: Log entries should be made and method returns | ||
678 | 243 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
679 | 244 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
680 | 245 | |||
681 | 246 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
682 | 247 | def test_get_datagram_pending_zero_length(self, mock_log): | ||
683 | 248 | """ | ||
684 | 249 | Test get_datagram when pendingDatagramSize = 0 | ||
685 | 250 | """ | ||
686 | 251 | # GIVEN: Test setup | ||
687 | 252 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
688 | 253 | log_warn_calls = [call('(UDP) get_datagram() called when pending data size is 0')] | ||
689 | 254 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
690 | 255 | call('(UDP) get_datagram() - Receiving data')] | ||
691 | 256 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram: | ||
692 | 257 | mock_datagram.return_value = 0 | ||
693 | 258 | |||
694 | 259 | # WHEN: get_datagram called with 0 bytes ready | ||
695 | 260 | pjlink_udp.get_datagram() | ||
696 | 261 | |||
697 | 262 | # THEN: Log entries should be made and method returns | ||
698 | 263 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
699 | 264 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
700 | 265 | |||
701 | 266 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
702 | 267 | def test_process_ackn_duplicate(self, mock_log): | ||
703 | 268 | """ | ||
704 | 269 | Test process_ackn method with multiple calls with same data | ||
705 | 270 | """ | ||
706 | 271 | # GIVEN: Test setup | ||
707 | 272 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
708 | 273 | check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}} | ||
709 | 274 | log_warn_calls = [call('(UDP) Host {host} already replied - ignoring'.format(host=TEST1_DATA['ip']))] | ||
710 | 275 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
711 | 276 | call('(UDP) Processing ACKN packet'), | ||
712 | 277 | call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip'])), | ||
713 | 278 | call('(UDP) Processing ACKN packet')] | ||
714 | 279 | |||
715 | 280 | # WHEN: process_ackn called twice with same data | ||
716 | 281 | pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) | ||
717 | 282 | pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) | ||
718 | 283 | |||
719 | 284 | # THEN: pjlink_udp.ack_list should equal test_list | ||
720 | 285 | # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? | ||
721 | 286 | if pjlink_udp.ackn_list != check_list: | ||
722 | 287 | # Check this way so we can print differences to stdout | ||
723 | 288 | print('\nackn_list: ', pjlink_udp.ackn_list) | ||
724 | 289 | print('test_list: ', check_list) | ||
725 | 290 | assert pjlink_udp.ackn_list == check_list | ||
726 | 291 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
727 | 292 | mock_log.warn.assert_has_calls(log_warn_calls) | ||
728 | 293 | |||
729 | 294 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
730 | 295 | def test_process_ackn_multiple(self, mock_log): | ||
731 | 296 | """ | ||
732 | 297 | Test process_ackn method with multiple calls | ||
733 | 298 | """ | ||
734 | 299 | # GIVEN: Test setup | ||
735 | 300 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
736 | 301 | check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}, | ||
737 | 302 | TEST2_DATA['ip']: {'data': TEST2_DATA['mac_adx'], 'port': PJLINK_PORT}} | ||
738 | 303 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
739 | 304 | call('(UDP) Processing ACKN packet'), | ||
740 | 305 | call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip'])), | ||
741 | 306 | call('(UDP) Processing ACKN packet'), | ||
742 | 307 | call('(UDP) Adding {host} to ACKN list'.format(host=TEST2_DATA['ip']))] | ||
743 | 308 | |||
744 | 309 | # WHEN: process_ackn called twice with different data | ||
745 | 310 | pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) | ||
746 | 311 | pjlink_udp.process_ackn(data=TEST2_DATA['mac_adx'], host=TEST2_DATA['ip'], port=PJLINK_PORT) | ||
747 | 312 | |||
748 | 313 | # THEN: pjlink_udp.ack_list should equal test_list | ||
749 | 314 | # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? | ||
750 | 315 | if pjlink_udp.ackn_list != check_list: | ||
751 | 316 | # Check this way so we can print differences to stdout | ||
752 | 317 | print('\nackn_list: ', pjlink_udp.ackn_list) | ||
753 | 318 | print('test_list: ', check_list) | ||
754 | 319 | assert pjlink_udp.ackn_list == check_list | ||
755 | 320 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
756 | 321 | |||
757 | 322 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
758 | 323 | def test_process_ackn_single(self, mock_log): | ||
759 | 324 | """ | ||
760 | 325 | Test process_ackn method with single call | ||
761 | 326 | """ | ||
762 | 327 | # GIVEN: Test setup | ||
763 | 328 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
764 | 329 | check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}} | ||
765 | 330 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
766 | 331 | call('(UDP) Processing ACKN packet'), | ||
767 | 332 | call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip']))] | ||
768 | 333 | |||
769 | 334 | # WHEN: process_ackn called twice with different data | ||
770 | 335 | pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) | ||
771 | 336 | |||
772 | 337 | # THEN: pjlink_udp.ack_list should equal test_list | ||
773 | 338 | # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? | ||
774 | 339 | if pjlink_udp.ackn_list != check_list: | ||
775 | 340 | # Check this way so we can print differences to stdout | ||
776 | 341 | print('\nackn_list: ', pjlink_udp.ackn_list) | ||
777 | 342 | print('test_list: ', check_list) | ||
778 | 343 | assert pjlink_udp.ackn_list == check_list | ||
779 | 344 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
780 | 345 | |||
781 | 346 | @patch.object(openlp.core.projectors.pjlink, 'log') | ||
782 | 347 | def test_process_srch(self, mock_log): | ||
783 | 348 | """ | ||
784 | 349 | Test process_srch method | ||
785 | 350 | """ | ||
786 | 351 | # GIVEN: Test setup | ||
787 | 352 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) | ||
788 | 353 | log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), | ||
789 | 354 | call('(UDP) SRCH packet received - ignoring')] | ||
790 | 355 | |||
791 | 356 | # WHEN: process_srch called | ||
792 | 357 | pjlink_udp.process_srch(data=None, host=None, port=None) | ||
793 | 358 | |||
794 | 359 | # THEN: debug log entry should be entered | ||
795 | 360 | mock_log.debug.assert_has_calls(log_debug_calls) | ||
796 | 0 | 361 | ||
797 | === renamed file 'tests/functional/openlp_core/common/test_projector_utilities.py' => 'tests/openlp_core/projectors/test_projector_utilities.py' | |||
798 | === renamed file 'tests/interfaces/openlp_core/ui/test_projectoreditform.py' => 'tests/openlp_core/projectors/test_projectoreditform.py' | |||
799 | === renamed file 'tests/interfaces/openlp_core/ui/test_projectormanager.py' => 'tests/openlp_core/projectors/test_projectormanager.py' | |||
800 | === renamed file 'tests/interfaces/openlp_core/ui/test_projectorsourceform.py' => 'tests/openlp_core/projectors/test_projectorsourceform.py' | |||
801 | --- tests/interfaces/openlp_core/ui/test_projectorsourceform.py 2017-12-29 09:15:48 +0000 | |||
802 | +++ tests/openlp_core/projectors/test_projectorsourceform.py 2018-02-12 01:05:51 +0000 | |||
803 | @@ -125,7 +125,6 @@ | |||
804 | 125 | select_form = SourceSelectSingle(parent=None, projectordb=self.projectordb) | 125 | select_form = SourceSelectSingle(parent=None, projectordb=self.projectordb) |
805 | 126 | select_form.edit = True | 126 | select_form.edit = True |
806 | 127 | select_form.exec(projector=self.projector) | 127 | select_form.exec(projector=self.projector) |
807 | 128 | projector = select_form.projector | ||
808 | 129 | 128 | ||
809 | 130 | # THEN: Verify all 4 buttons are available | 129 | # THEN: Verify all 4 buttons are available |
810 | 131 | assert len(select_form.button_box.buttons()) == 4, \ | 130 | assert len(select_form.button_box.buttons()) == 4, \ |
811 | @@ -144,7 +143,6 @@ | |||
812 | 144 | select_form = SourceSelectSingle(parent=None, projectordb=self.projectordb) | 143 | select_form = SourceSelectSingle(parent=None, projectordb=self.projectordb) |
813 | 145 | select_form.edit = False | 144 | select_form.edit = False |
814 | 146 | select_form.exec(projector=self.projector) | 145 | select_form.exec(projector=self.projector) |
815 | 147 | projector = select_form.projector | ||
816 | 148 | 146 | ||
817 | 149 | # THEN: Verify only 2 buttons are available | 147 | # THEN: Verify only 2 buttons are available |
818 | 150 | assert len(select_form.button_box.buttons()) == 2, \ | 148 | assert len(select_form.button_box.buttons()) == 2, \ |
819 | 151 | 149 | ||
820 | === modified file 'tests/resources/projector/data.py' | |||
821 | --- tests/resources/projector/data.py 2017-12-29 09:15:48 +0000 | |||
822 | +++ tests/resources/projector/data.py 2018-02-12 01:05:51 +0000 | |||
823 | @@ -45,7 +45,8 @@ | |||
824 | 45 | serial_no='Serial Number 1', | 45 | serial_no='Serial Number 1', |
825 | 46 | sw_version='Version 1', | 46 | sw_version='Version 1', |
826 | 47 | model_filter='Filter type 1', | 47 | model_filter='Filter type 1', |
828 | 48 | model_lamp='Lamp type 1') | 48 | model_lamp='Lamp type 1', |
829 | 49 | mac_adx='11:11:11:11:11:11') | ||
830 | 49 | 50 | ||
831 | 50 | TEST2_DATA = dict(ip='222.222.222.222', | 51 | TEST2_DATA = dict(ip='222.222.222.222', |
832 | 51 | port='2222', | 52 | port='2222', |
833 | @@ -56,7 +57,8 @@ | |||
834 | 56 | serial_no='Serial Number 2', | 57 | serial_no='Serial Number 2', |
835 | 57 | sw_version='Version 2', | 58 | sw_version='Version 2', |
836 | 58 | model_filter='Filter type 2', | 59 | model_filter='Filter type 2', |
838 | 59 | model_lamp='Lamp type 2') | 60 | model_lamp='Lamp type 2', |
839 | 61 | mac_adx='22:22:22:22:22:22') | ||
840 | 60 | 62 | ||
841 | 61 | TEST3_DATA = dict(ip='333.333.333.333', | 63 | TEST3_DATA = dict(ip='333.333.333.333', |
842 | 62 | port='3333', | 64 | port='3333', |
843 | @@ -67,7 +69,8 @@ | |||
844 | 67 | serial_no='Serial Number 3', | 69 | serial_no='Serial Number 3', |
845 | 68 | sw_version='Version 3', | 70 | sw_version='Version 3', |
846 | 69 | model_filter='Filter type 3', | 71 | model_filter='Filter type 3', |
848 | 70 | model_lamp='Lamp type 3') | 72 | model_lamp='Lamp type 3', |
849 | 73 | mac_adx='33:33:33:33:33:33') | ||
850 | 71 | 74 | ||
851 | 72 | TEST_VIDEO_CODES = { | 75 | TEST_VIDEO_CODES = { |
852 | 73 | '11': 'RGB 1', | 76 | '11': 'RGB 1', |
One question and a request to refactor.