Merge lp:~alisonken1/openlp/pjlink2-q into lp:openlp
- pjlink2-q
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~alisonken1/openlp/pjlink2-q |
Merge into: | lp:openlp |
Diff against target: |
1482 lines (+437/-501) 8 files modified
openlp/core/projectors/constants.py (+53/-26) openlp/core/projectors/editform.py (+42/-27) openlp/core/projectors/manager.py (+3/-18) openlp/core/projectors/pjlink.py (+158/-149) tests/openlp_core/projectors/test_projector_db.py (+35/-2) tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py (+21/-21) tests/openlp_core/projectors/test_projector_pjlink_commands_02.py (+115/-4) tests/openlp_core/projectors/test_projector_pjlink_udp.py (+10/-254) |
To merge this branch: | bzr merge lp:~alisonken1/openlp/pjlink2-q |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Bentley | Pending | ||
Phill | Pending | ||
Review via email: mp+343668@code.launchpad.net |
This proposal supersedes a proposal from 2018-03-24.
This proposal has been superseded by a proposal from 2018-04-20.
Commit message
PJLink2 update Q
Description of the change
PJLink2 update Q
-------
lp:~alisonken1/openlp/pjlink2-q (revision 2818)
https:/
https:/
https:/
https:/
https:/
https:/
https:/
https:/
-------
- Fix test_projector_
creating self.main_window steps
- Pep8 on openlp/
- Collapse import from projector.constants from line-per-item to multi-items-
- Change pjlink_functions to include class version for projector instance in command
- Set projector.editform to only allow editing IP address field for new entry only (used as db key entry)
- Collapse projector.manager imports from entry-per-line to compact import
- projector.pjlink:
- Merge pjlink_
- Change pjlink_functions to add instance-specific version to commands
- Fix command checks to changed pjlink_funcions
- Update process_clss to update PJLink version in pjlink_functions
- Update reset_information to update PJLink version in pjlink_functions
- renamed test_projectors
- renamed test_projectore
- Fix projector tests
- Fix list creation in constants (remove unneeded comma)
- Rename editform ip_text_show label to ip_text_label
- Refactor editform IP address check
- Add TODO on commented code block for breaking incoming packet into parts
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Ken Roberts (alisonken1) wrote : Posted in a previous version of this proposal | # |
> Sorry will clash with one of my fixes which has been merged
>
> See question
>> 'ACKN': {'version': ['2', ],
>> + 'default': '2',
>Why do we have a missing slot?
2 new commands in PJLink are only valid for version 2 and have no version 1 equivalent.
Missing slot is to maintain compatibility with version checker.
>> - def process_clss(self, data):
>> + def process_clss(self, data, *args, **kwargs):
>why args
Some commands take host,port arguments but not all of them do.
Since there is a common entry point, need to keep availability of consuming extra args/kwargs without causing exception due to extra parameters.
(Yes, there should be no args passed only keyword args, but better safe than sorry)
Ken Roberts (alisonken1) wrote : Posted in a previous version of this proposal | # |
which fix is clashing? I tried a merge from trunk and it merged fine.
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Looks OK but projectors is not my strong point.
Phill (phill-ridout) wrote : Posted in a previous version of this proposal | # |
A few issues / questions. See in line.
- 2818. By Ken Roberts
-
PJLink2 update Q
Unmerged revisions
Preview Diff
1 | === modified file 'openlp/core/projectors/constants.py' |
2 | --- openlp/core/projectors/constants.py 2018-01-03 00:35:14 +0000 |
3 | +++ openlp/core/projectors/constants.py 2018-04-20 06:05:02 +0000 |
4 | @@ -154,110 +154,137 @@ |
5 | S_INFO |
6 | ] |
7 | |
8 | -# NOTE: Changed format to account for some commands are both class 1 and 2 |
9 | +# NOTE: Changed format to account for some commands are both class 1 and 2. |
10 | +# Make sure the sequence of 'version' is lowest-to-highest. |
11 | PJLINK_VALID_CMD = { |
12 | - 'ACKN': {'version': ['2', ], |
13 | + 'ACKN': {'version': ['2'], |
14 | + 'default': '2', |
15 | 'description': translate('OpenLP.PJLinkConstants', |
16 | 'Acknowledge a PJLink SRCH command - returns MAC address.') |
17 | }, |
18 | - 'AVMT': {'version': ['1', ], |
19 | + 'AVMT': {'version': ['1'], |
20 | + 'default': '1', |
21 | 'description': translate('OpenLP.PJLinkConstants', |
22 | 'Blank/unblank video and/or mute audio.') |
23 | }, |
24 | - 'CLSS': {'version': ['1', ], |
25 | + 'CLSS': {'version': ['1'], |
26 | + 'default': '1', |
27 | 'description': translate('OpenLP.PJLinkConstants', |
28 | 'Query projector PJLink class support.') |
29 | }, |
30 | 'ERST': {'version': ['1', '2'], |
31 | + 'default': '1', |
32 | 'description': translate('OpenLP.PJLinkConstants', |
33 | 'Query error status from projector. ' |
34 | 'Returns fan/lamp/temp/cover/filter/other error status.') |
35 | }, |
36 | - 'FILT': {'version': ['2', ], |
37 | + 'FILT': {'version': ['2'], |
38 | + 'default': '1', |
39 | 'description': translate('OpenLP.PJLinkConstants', |
40 | 'Query number of hours on filter.') |
41 | }, |
42 | - 'FREZ': {'version': ['2', ], |
43 | + 'FREZ': {'version': ['2'], |
44 | + 'default': '1', |
45 | 'description': translate('OpenLP.PJLinkConstants', |
46 | 'Freeze or unfreeze current image being projected.') |
47 | }, |
48 | - 'INF1': {'version': ['1', ], |
49 | + 'INF1': {'version': ['1'], |
50 | + 'default': '1', |
51 | 'description': translate('OpenLP.PJLinkConstants', |
52 | 'Query projector manufacturer name.') |
53 | }, |
54 | - 'INF2': {'version': ['1', ], |
55 | + 'INF2': {'version': ['1'], |
56 | + 'default': '1', |
57 | 'description': translate('OpenLP.PJLinkConstants', |
58 | 'Query projector product name.') |
59 | }, |
60 | - 'INFO': {'version': ['1', ], |
61 | + 'INFO': {'version': ['1'], |
62 | + 'default': '1', |
63 | 'description': translate('OpenLP.PJLinkConstants', |
64 | 'Query projector for other information set by manufacturer.') |
65 | }, |
66 | - 'INNM': {'version': ['2', ], |
67 | + 'INNM': {'version': ['2'], |
68 | + 'default': '2', |
69 | 'description': translate('OpenLP.PJLinkConstants', |
70 | 'Query specified input source name') |
71 | }, |
72 | - 'INPT': {'version': ['1', ], |
73 | + 'INPT': {'version': ['1'], |
74 | + 'default': '1', |
75 | 'description': translate('OpenLP.PJLinkConstants', |
76 | 'Switch to specified video source.') |
77 | }, |
78 | - 'INST': {'version': ['1', ], |
79 | + 'INST': {'version': ['1'], |
80 | + 'default': '1', |
81 | 'description': translate('OpenLP.PJLinkConstants', |
82 | 'Query available input sources.') |
83 | }, |
84 | - 'IRES': {'version:': ['2', ], |
85 | + 'IRES': {'version': ['2'], |
86 | + 'default': '2', |
87 | 'description': translate('OpenLP.PJLinkConstants', |
88 | 'Query current input resolution.') |
89 | }, |
90 | - 'LAMP': {'version': ['1', ], |
91 | + 'LAMP': {'version': ['1'], |
92 | + 'default': '1', |
93 | 'description': translate('OpenLP.PJLinkConstants', |
94 | 'Query lamp time and on/off status. Multiple lamps supported.') |
95 | }, |
96 | - 'LKUP': {'version': ['2', ], |
97 | + 'LKUP': {'version': ['2'], |
98 | + 'default': '2', |
99 | 'description': translate('OpenLP.PJLinkConstants', |
100 | 'UDP Status - Projector is now available on network. Includes MAC address.') |
101 | }, |
102 | - 'MVOL': {'version': ['2', ], |
103 | + 'MVOL': {'version': ['2'], |
104 | + 'default': '1', |
105 | 'description': translate('OpenLP.PJLinkConstants', |
106 | 'Adjust microphone volume by 1 step.') |
107 | }, |
108 | - 'NAME': {'version': ['1', ], |
109 | + 'NAME': {'version': ['1'], |
110 | + 'default': '1', |
111 | 'description': translate('OpenLP.PJLinkConstants', |
112 | 'Query customer-set projector name.') |
113 | }, |
114 | - 'PJLINK': {'version': ['1', ], |
115 | + 'PJLINK': {'version': ['1'], |
116 | + 'default': '1', |
117 | 'description': translate('OpenLP.PJLinkConstants', |
118 | 'Initial connection with authentication/no authentication request.') |
119 | }, |
120 | - 'POWR': {'version': ['1', ], |
121 | + 'POWR': {'version': ['1'], |
122 | + 'default': '1', |
123 | 'description': translate('OpenLP.PJLinkConstants', |
124 | 'Turn lamp on or off/standby.') |
125 | }, |
126 | - 'RFIL': {'version': ['2', ], |
127 | + 'RFIL': {'version': ['2'], |
128 | + 'default': '2', |
129 | 'description': translate('OpenLP.PJLinkConstants', |
130 | 'Query replacement air filter model number.') |
131 | }, |
132 | - 'RLMP': {'version': ['2', ], |
133 | + 'RLMP': {'version': ['2'], |
134 | + 'default': '2', |
135 | 'description': translate('OpenLP.PJLinkConstants', |
136 | 'Query replacement lamp model number.') |
137 | }, |
138 | - 'RRES': {'version': ['2', ], |
139 | + 'RRES': {'version': ['2'], |
140 | + 'default': '2', |
141 | 'description': translate('OpenLP.PJLinkConstants', |
142 | 'Query recommended resolution.') |
143 | }, |
144 | - 'SNUM': {'version': ['2', ], |
145 | + 'SNUM': {'version': ['2'], |
146 | + 'default': '2', |
147 | 'description': translate('OpenLP.PJLinkConstants', |
148 | 'Query projector serial number.') |
149 | }, |
150 | - 'SRCH': {'version': ['2', ], |
151 | + 'SRCH': {'version': ['2'], |
152 | + 'default': '2', |
153 | 'description': translate('OpenLP.PJLinkConstants', |
154 | 'UDP broadcast search request for available projectors. Reply is ACKN.') |
155 | }, |
156 | - 'SVER': {'version': ['2', ], |
157 | + 'SVER': {'version': ['2'], |
158 | + 'default': '2', |
159 | 'description': translate('OpenLP.PJLinkConstants', |
160 | 'Query projector software version number.') |
161 | }, |
162 | - 'SVOL': {'version': ['2', ], |
163 | + 'SVOL': {'version': ['2'], |
164 | + 'default': '2', |
165 | 'description': translate('OpenLP.PJLinkConstants', |
166 | 'Adjust speaker volume by 1 step.') |
167 | } |
168 | |
169 | === modified file 'openlp/core/projectors/editform.py' |
170 | --- openlp/core/projectors/editform.py 2017-12-29 09:15:48 +0000 |
171 | +++ openlp/core/projectors/editform.py 2018-04-20 06:05:02 +0000 |
172 | @@ -58,10 +58,15 @@ |
173 | # IP Address |
174 | self.ip_label = QtWidgets.QLabel(edit_projector_dialog) |
175 | self.ip_label.setObjectName('projector_edit_ip_label') |
176 | - self.ip_text = QtWidgets.QLineEdit(edit_projector_dialog) |
177 | - self.ip_text.setObjectName('projector_edit_ip_text') |
178 | + self.ip_text_edit = QtWidgets.QLineEdit(edit_projector_dialog) |
179 | + self.ip_text_edit.setObjectName('projector_edit_ip_text') |
180 | + self.ip_text_label = QtWidgets.QLabel(edit_projector_dialog) |
181 | + self.ip_text_label.setObjectName('projector_show_ip_text') |
182 | self.dialog_layout.addWidget(self.ip_label, 0, 0) |
183 | - self.dialog_layout.addWidget(self.ip_text, 0, 1) |
184 | + # For new projector, use edit widget |
185 | + self.dialog_layout.addWidget(self.ip_text_edit, 0, 1) |
186 | + # For edit projector, use show widget |
187 | + self.dialog_layout.addWidget(self.ip_text_label, 0, 1) |
188 | # Port number |
189 | self.port_label = QtWidgets.QLabel(edit_projector_dialog) |
190 | self.port_label.setObjectName('projector_edit_ip_label') |
191 | @@ -111,8 +116,8 @@ |
192 | title = translate('OpenLP.ProjectorEditForm', 'Edit Projector') |
193 | edit_projector_dialog.setWindowTitle(title) |
194 | self.ip_label.setText(translate('OpenLP.ProjectorEditForm', 'IP Address')) |
195 | - self.ip_text.setText(self.projector.ip) |
196 | - self.ip_text.setFocus() |
197 | + self.ip_text_edit.setText(self.projector.ip) |
198 | + self.ip_text_label.setText(self.projector.ip) |
199 | self.port_label.setText(translate('OpenLP.ProjectorEditForm', 'Port Number')) |
200 | self.port_text.setText(str(self.projector.port)) |
201 | self.pin_label.setText(translate('OpenLP.ProjectorEditForm', 'PIN')) |
202 | @@ -131,7 +136,7 @@ |
203 | Class to add or edit a projector entry in the database. |
204 | |
205 | Fields that are editable: |
206 | - ip = Column(String(100)) |
207 | + ip = Column(String(100)) (Only edit for new projector) |
208 | port = Column(String(8)) |
209 | pin = Column(String(20)) |
210 | name = Column(String(20)) |
211 | @@ -154,9 +159,16 @@ |
212 | if projector is None: |
213 | self.projector = Projector() |
214 | self.new_projector = True |
215 | + self.ip_text_edit.setVisible(True) |
216 | + self.ip_text_edit.setFocus() |
217 | + self.ip_text_label.setVisible(False) |
218 | else: |
219 | self.projector = projector |
220 | self.new_projector = False |
221 | + self.ip_text_edit.setVisible(False) |
222 | + self.ip_text_label.setVisible(True) |
223 | + # Since it's already defined, IP address is unchangeable, so focus on port number |
224 | + self.port_text.setFocus() |
225 | self.retranslateUi(self) |
226 | reply = QtWidgets.QDialog.exec(self) |
227 | return reply |
228 | @@ -187,30 +199,32 @@ |
229 | record=record.id))) |
230 | valid = False |
231 | return |
232 | - adx = self.ip_text.text() |
233 | - valid = verify_ip_address(adx) |
234 | - if valid: |
235 | - ip = self.projectordb.get_projector_by_ip(adx) |
236 | - if ip is None: |
237 | - valid = True |
238 | - self.new_projector = True |
239 | - elif ip.id != self.projector.id: |
240 | + if self.new_projector: |
241 | + # Only validate a new entry - otherwise it's been previously verified |
242 | + adx = self.ip_text_edit.text() |
243 | + valid = verify_ip_address(adx) |
244 | + if valid: |
245 | + # With a valid IP - check if it's already in database so we don't duplicate |
246 | + ip = self.projectordb.get_projector_by_ip(adx) |
247 | + if ip is None: |
248 | + valid = True |
249 | + self.new_projector = True |
250 | + elif ip.id != self.projector.id: |
251 | + QtWidgets.QMessageBox.warning(self, |
252 | + translate('OpenLP.ProjectorWizard', 'Duplicate IP Address'), |
253 | + translate('OpenLP.ProjectorWizard', |
254 | + 'IP address "{ip}"<br />is already in the database ' |
255 | + 'as ID {data}.<br /><br />Please Enter a different ' |
256 | + 'IP address.'.format(ip=adx, data=ip.id))) |
257 | + return |
258 | + else: |
259 | QtWidgets.QMessageBox.warning(self, |
260 | - translate('OpenLP.ProjectorWizard', 'Duplicate IP Address'), |
261 | + translate('OpenLP.ProjectorWizard', 'Invalid IP Address'), |
262 | translate('OpenLP.ProjectorWizard', |
263 | - 'IP address "{ip}"<br />is already in the database ' |
264 | - 'as ID {data}.<br /><br />Please Enter a different ' |
265 | - 'IP address.'.format(ip=adx, data=ip.id))) |
266 | + 'IP address "{ip}"<br>is not a valid IP address.' |
267 | + '<br /><br />Please enter a valid IP address.'.format(ip=adx))) |
268 | valid = False |
269 | return |
270 | - else: |
271 | - QtWidgets.QMessageBox.warning(self, |
272 | - translate('OpenLP.ProjectorWizard', 'Invalid IP Address'), |
273 | - translate('OpenLP.ProjectorWizard', |
274 | - 'IP address "{ip}"<br>is not a valid IP address.' |
275 | - '<br /><br />Please enter a valid IP address.'.format(ip=adx))) |
276 | - valid = False |
277 | - return |
278 | port = int(self.port_text.text()) |
279 | if port < 1000 or port > 32767: |
280 | QtWidgets.QMessageBox.warning(self, |
281 | @@ -223,7 +237,8 @@ |
282 | 'Default PJLink port is {port}'.format(port=PJLINK_PORT))) |
283 | valid = False |
284 | if valid: |
285 | - self.projector.ip = self.ip_text.text() |
286 | + if self.new_projector: |
287 | + self.projector.ip = self.ip_text_edit.text() |
288 | self.projector.pin = self.pin_text.text() |
289 | self.projector.port = int(self.port_text.text()) |
290 | self.projector.name = self.name_text.text() |
291 | |
292 | === modified file 'openlp/core/projectors/manager.py' |
293 | --- openlp/core/projectors/manager.py 2018-02-11 11:42:13 +0000 |
294 | +++ openlp/core/projectors/manager.py 2018-04-20 06:05:02 +0000 |
295 | @@ -35,24 +35,9 @@ |
296 | from openlp.core.common.settings import Settings |
297 | from openlp.core.lib.ui import create_widget_action |
298 | from openlp.core.projectors import DialogSourceStyle |
299 | -from openlp.core.projectors.constants import \ |
300 | - E_AUTHENTICATION, \ |
301 | - E_ERROR, \ |
302 | - E_NETWORK, \ |
303 | - E_NOT_CONNECTED, \ |
304 | - E_UNKNOWN_SOCKET_ERROR, \ |
305 | - S_CONNECTED, \ |
306 | - S_CONNECTING, \ |
307 | - S_COOLDOWN, \ |
308 | - S_INITIALIZE, \ |
309 | - S_NOT_CONNECTED, \ |
310 | - S_OFF, \ |
311 | - S_ON, \ |
312 | - S_STANDBY, \ |
313 | - S_WARMUP, \ |
314 | - STATUS_CODE, \ |
315 | - STATUS_MSG, \ |
316 | - QSOCKET_STATE |
317 | +from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, \ |
318 | + E_UNKNOWN_SOCKET_ERROR, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, \ |
319 | + S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG, QSOCKET_STATE |
320 | |
321 | from openlp.core.projectors.db import ProjectorDB |
322 | from openlp.core.projectors.editform import ProjectorEditForm |
323 | |
324 | === modified file 'openlp/core/projectors/pjlink.py' |
325 | --- openlp/core/projectors/pjlink.py 2018-02-11 11:42:13 +0000 |
326 | +++ openlp/core/projectors/pjlink.py 2018-04-20 06:05:02 +0000 |
327 | @@ -57,8 +57,7 @@ |
328 | from openlp.core.projectors.constants import CONNECTION_ERRORS, PJLINK_CLASS, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \ |
329 | PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PREFIX, PJLINK_PORT, PJLINK_POWR_STATUS, \ |
330 | PJLINK_SUFFIX, PJLINK_VALID_CMD, PROJECTOR_STATE, STATUS_CODE, STATUS_MSG, QSOCKET_STATE, \ |
331 | - E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, \ |
332 | - E_SOCKET_TIMEOUT, \ |
333 | + E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT, \ |
334 | S_CONNECTED, S_CONNECTING, S_NOT_CONNECTED, S_OFF, S_OK, S_ON |
335 | |
336 | log = logging.getLogger(__name__) |
337 | @@ -93,22 +92,9 @@ |
338 | self.projector_list = projector_list |
339 | self.port = port |
340 | # Local defines |
341 | - self.ackn_list = {} # Replies from online projetors |
342 | self.search_active = False |
343 | self.search_time = 30000 # 30 seconds for allowed time |
344 | self.search_timer = QtCore.QTimer() |
345 | - # New commands available in PJLink Class 2 |
346 | - # ACKN/SRCH is processed here since it's used to find available projectors |
347 | - # Other commands are processed by the individual projector instances |
348 | - self.pjlink_udp_functions = { |
349 | - 'ACKN': self.process_ackn, # Class 2, command is 'SRCH' |
350 | - 'ERST': None, # Class 1/2 |
351 | - 'INPT': None, # Class 1/2 |
352 | - 'LKUP': None, # Class 2 (reply only - no cmd) |
353 | - 'POWR': None, # Class 1/2 |
354 | - 'SRCH': self.process_srch # Class 2 (reply is ACKN) |
355 | - } |
356 | - |
357 | self.readyRead.connect(self.get_datagram) |
358 | log.debug('(UDP) PJLinkUDP() Initialized') |
359 | |
360 | @@ -118,88 +104,26 @@ |
361 | Retrieve packet and basic checks |
362 | """ |
363 | log.debug('(UDP) get_datagram() - Receiving data') |
364 | - read = self.pendingDatagramSize() |
365 | - if read < 0: |
366 | - log.warn('(UDP) No data (-1)') |
367 | + read_size = self.pendingDatagramSize() |
368 | + if read_size < 0: |
369 | + log.warning('(UDP) No data (-1)') |
370 | return |
371 | - if read < 1: |
372 | - log.warn('(UDP) get_datagram() called when pending data size is 0') |
373 | + if read_size < 1: |
374 | + log.warning('(UDP) get_datagram() called when pending data size is 0') |
375 | return |
376 | data, peer_address, peer_port = self.readDatagram(self.pendingDatagramSize()) |
377 | log.debug('(UDP) {size} bytes received from {adx} on port {port}'.format(size=len(data), |
378 | adx=peer_address, |
379 | port=peer_port)) |
380 | log.debug('(UDP) packet "{data}"'.format(data=data)) |
381 | - if len(data) < 0: |
382 | - log.warn('(UDP) No data (-1)') |
383 | - return |
384 | - elif len(data) < 8: |
385 | - # Minimum packet is '%2CCCC=' |
386 | - log.warn('(UDP) Invalid packet - not enough data') |
387 | - return |
388 | - elif data is None: |
389 | - log.warn('(UDP) No data (None)') |
390 | - return |
391 | - elif len(data) > PJLINK_MAX_PACKET: |
392 | - log.warn('(UDP) Invalid packet - length too long') |
393 | - return |
394 | - elif not data.startswith(PJLINK_PREFIX): |
395 | - log.warn('(UDP) Invalid packet - does not start with PJLINK_PREFIX') |
396 | - return |
397 | - elif data[1] != '2': |
398 | - log.warn('(UDP) Invalid packet - missing/invalid PJLink class version') |
399 | - return |
400 | - elif data[6] != '=': |
401 | - log.warn('(UDP) Invalid packet - separator missing') |
402 | - return |
403 | - # First two characters are header information we don't need at this time |
404 | - cmd, data = data[2:].split('=') |
405 | - if cmd not in self.pjlink_udp_functions: |
406 | - log.warn('(UDP) Invalid packet - not a valid PJLink UDP reply') |
407 | - return |
408 | - if self.pjlink_udp_functions[cmd] is not None: |
409 | - log.debug('(UDP) Processing {cmd} with "{data}"'.format(cmd=cmd, data=data)) |
410 | - return self.pjlink_udp_functions[cmd](data=data, host=peer_address, port=peer_port) |
411 | - else: |
412 | - log.debug('(UDP) Checking projector list for ip {host} to process'.format(host=peer_address)) |
413 | - for projector in self.projector_list: |
414 | - if peer_address == projector.ip: |
415 | - if cmd not in projector.pjlink_functions: |
416 | - log.error('(UDP) Could not find method to process ' |
417 | - '"{cmd}" in {host}'.format(cmd=cmd, host=projector.ip)) |
418 | - return |
419 | - log.debug('(UDP) Calling "{cmd}" in {host}'.format(cmd=cmd, host=projector.ip)) |
420 | - return projector.pjlink_functions[cmd](data=data) |
421 | - log.warn('(UDP) Could not find projector with ip {ip} to process packet'.format(ip=peer_address)) |
422 | - return |
423 | - |
424 | - def process_ackn(self, data, host, port): |
425 | - """ |
426 | - Process the ACKN command. |
427 | - |
428 | - :param data: Data in packet |
429 | - :param host: IP address of sending host |
430 | - :param port: Port received on |
431 | - """ |
432 | - log.debug('(UDP) Processing ACKN packet') |
433 | - if host not in self.ackn_list: |
434 | - log.debug('(UDP) Adding {host} to ACKN list'.format(host=host)) |
435 | - self.ackn_list[host] = {'data': data, |
436 | - 'port': port} |
437 | - else: |
438 | - log.warn('(UDP) Host {host} already replied - ignoring'.format(host=host)) |
439 | - |
440 | - def process_srch(self, data, host, port): |
441 | - """ |
442 | - Process the SRCH command. |
443 | - |
444 | - SRCH is processed by terminals so we ignore any packet. |
445 | - |
446 | - :param data: Data in packet |
447 | - :param host: IP address of sending host |
448 | - :param port: Port received on |
449 | - """ |
450 | - log.debug('(UDP) SRCH packet received - ignoring') |
451 | + # Send to appropriate instance to process packet |
452 | + log.debug('(UDP) Checking projector list for ip {host} to process'.format(host=peer_address)) |
453 | + for projector in self.projector_list: |
454 | + if peer_address == projector.ip: |
455 | + # Dispatch packet to appropriate remote instance |
456 | + log.debug('(UDP) Dispatching packet to {host}'.format(host=projector.entry.name)) |
457 | + return projector.get_data(buff=data, ip=peer_address, host=peer_address, port=peer_port) |
458 | + log.warning('(UDP) Could not find projector with ip {ip} to process packet'.format(ip=peer_address)) |
459 | return |
460 | |
461 | def search_start(self): |
462 | @@ -224,6 +148,8 @@ |
463 | """ |
464 | Process replies from PJLink projector. |
465 | """ |
466 | + # List of IP addresses and mac addresses found via UDP search command |
467 | + ackn_list = [] |
468 | |
469 | def __init__(self, *args, **kwargs): |
470 | """ |
471 | @@ -231,24 +157,47 @@ |
472 | """ |
473 | log.debug('PJlinkCommands(args={args} kwargs={kwargs})'.format(args=args, kwargs=kwargs)) |
474 | super().__init__() |
475 | - # Map PJLink command to method |
476 | + # Map PJLink command to method and include pjlink class version for this instance |
477 | + # Default initial pjlink class version is '1' |
478 | self.pjlink_functions = { |
479 | - 'AVMT': self.process_avmt, |
480 | - 'CLSS': self.process_clss, |
481 | - 'ERST': self.process_erst, |
482 | - 'INFO': self.process_info, |
483 | - 'INF1': self.process_inf1, |
484 | - 'INF2': self.process_inf2, |
485 | - 'INPT': self.process_inpt, |
486 | - 'INST': self.process_inst, |
487 | - 'LAMP': self.process_lamp, |
488 | - 'NAME': self.process_name, |
489 | - 'PJLINK': self.process_pjlink, |
490 | - 'POWR': self.process_powr, |
491 | - 'SNUM': self.process_snum, |
492 | - 'SVER': self.process_sver, |
493 | - 'RFIL': self.process_rfil, |
494 | - 'RLMP': self.process_rlmp |
495 | + 'ACKN': {"method": self.process_ackn, # Class 2 (command is SRCH) |
496 | + "version": "2"}, |
497 | + 'AVMT': {"method": self.process_avmt, |
498 | + "version": "1"}, |
499 | + 'CLSS': {"method": self.process_clss, |
500 | + "version": "1"}, |
501 | + 'ERST': {"method": self.process_erst, |
502 | + "version": "1"}, |
503 | + 'INFO': {"method": self.process_info, |
504 | + "version": "1"}, |
505 | + 'INF1': {"method": self.process_inf1, |
506 | + "version": "1"}, |
507 | + 'INF2': {"method": self.process_inf2, |
508 | + "version": "1"}, |
509 | + 'INPT': {"method": self.process_inpt, |
510 | + "version": "1"}, |
511 | + 'INST': {"method": self.process_inst, |
512 | + "version": "1"}, |
513 | + 'LAMP': {"method": self.process_lamp, |
514 | + "version": "1"}, |
515 | + 'LKUP': {"method": self.process_lkup, # Class 2 (reply only - no cmd) |
516 | + "version": "2"}, |
517 | + 'NAME': {"method": self.process_name, |
518 | + "version": "1"}, |
519 | + 'PJLINK': {"method": self.process_pjlink, |
520 | + "version": "1"}, |
521 | + 'POWR': {"method": self.process_powr, |
522 | + "version": "1"}, |
523 | + 'SNUM': {"method": self.process_snum, |
524 | + "version": "1"}, |
525 | + 'SRCH': {"method": self.process_srch, # Class 2 (reply is ACKN) |
526 | + "version": "2"}, |
527 | + 'SVER': {"method": self.process_sver, |
528 | + "version": "1"}, |
529 | + 'RFIL': {"method": self.process_rfil, |
530 | + "version": "1"}, |
531 | + 'RLMP': {"method": self.process_rlmp, |
532 | + "version": "1"} |
533 | } |
534 | |
535 | def reset_information(self): |
536 | @@ -287,8 +236,11 @@ |
537 | self.send_busy = False |
538 | self.send_queue = [] |
539 | self.priority_queue = [] |
540 | + # Reset default version in command routing dict |
541 | + for cmd in self.pjlink_functions: |
542 | + self.pjlink_functions[cmd]["version"] = PJLINK_VALID_CMD[cmd]['default'] |
543 | |
544 | - def process_command(self, cmd, data): |
545 | + def process_command(self, cmd, data, *args, **kwargs): |
546 | """ |
547 | Verifies any return error code. Calls the appropriate command handler. |
548 | |
549 | @@ -320,9 +272,25 @@ |
550 | return self.change_status(status=E_AUTHENTICATION) |
551 | # Command checks already passed |
552 | log.debug('({ip}) Calling function for {cmd}'.format(ip=self.entry.name, cmd=cmd)) |
553 | - self.pjlink_functions[cmd](data=data) |
554 | - |
555 | - def process_avmt(self, data): |
556 | + self.pjlink_functions[cmd]["method"](data=data, *args, **kwargs) |
557 | + |
558 | + def process_ackn(self, data, host, port): |
559 | + """ |
560 | + Process the ACKN command. |
561 | + |
562 | + :param data: Data in packet |
563 | + :param host: IP address of sending host |
564 | + :param port: Port received on |
565 | + """ |
566 | + log.debug('({ip}) Processing ACKN packet'.format(ip=self.entry.name)) |
567 | + if host not in self.ackn_list: |
568 | + log.debug('({ip}) Adding {host} to ACKN list'.format(ip=self.entry.name, host=host)) |
569 | + self.ackn_list[host] = {'data': data, |
570 | + 'port': port} |
571 | + else: |
572 | + log.warning('({ip}) Host {host} already replied - ignoring'.format(ip=self.entry.name, host=host)) |
573 | + |
574 | + def process_avmt(self, data, *args, **kwargs): |
575 | """ |
576 | Process shutter and speaker status. See PJLink specification for format. |
577 | Update self.mute (audio) and self.shutter (video shutter). |
578 | @@ -351,7 +319,7 @@ |
579 | self.projectorUpdateIcons.emit() |
580 | return |
581 | |
582 | - def process_clss(self, data): |
583 | + def process_clss(self, data, *args, **kwargs): |
584 | """ |
585 | PJLink class that this projector supports. See PJLink specification for format. |
586 | Updates self.class. |
587 | @@ -367,12 +335,13 @@ |
588 | # Due to stupid projectors not following standards (Optoma, BenQ comes to mind), |
589 | # AND the different responses that can be received, the semi-permanent way to |
590 | # fix the class reply is to just remove all non-digit characters. |
591 | - try: |
592 | - clss = re.findall('\d', data)[0] # Should only be the first match |
593 | - except IndexError: |
594 | + chk = re.findall('\d', data) |
595 | + if len(chk) < 1: |
596 | log.error('({ip}) No numbers found in class version reply "{data}" - ' |
597 | 'defaulting to class "1"'.format(ip=self.entry.name, data=data)) |
598 | clss = '1' |
599 | + else: |
600 | + clss = chk[0] # Should only be the first match |
601 | elif not data.isdigit(): |
602 | log.error('({ip}) NAN CLSS version reply "{data}" - ' |
603 | 'defaulting to class "1"'.format(ip=self.entry.name, data=data)) |
604 | @@ -383,6 +352,11 @@ |
605 | log.debug('({ip}) Setting pjlink_class for this projector ' |
606 | 'to "{data}"'.format(ip=self.entry.name, |
607 | data=self.pjlink_class)) |
608 | + # Update method class versions |
609 | + for cmd in self.pjlink_functions: |
610 | + if self.pjlink_class in PJLINK_VALID_CMD[cmd]['version']: |
611 | + self.pjlink_functions[cmd]['version'] = self.pjlink_class |
612 | + |
613 | # Since we call this one on first connect, setup polling from here |
614 | if not self.no_poll: |
615 | log.debug('({ip}) process_pjlink(): Starting timer'.format(ip=self.entry.name)) |
616 | @@ -391,7 +365,7 @@ |
617 | |
618 | return |
619 | |
620 | - def process_erst(self, data): |
621 | + def process_erst(self, data, *args, **kwargs): |
622 | """ |
623 | Error status. See PJLink Specifications for format. |
624 | Updates self.projector_errors |
625 | @@ -443,7 +417,7 @@ |
626 | PJLINK_ERST_STATUS[other] |
627 | return |
628 | |
629 | - def process_inf1(self, data): |
630 | + def process_inf1(self, data, *args, **kwargs): |
631 | """ |
632 | Manufacturer name set in projector. |
633 | Updates self.manufacturer |
634 | @@ -455,7 +429,7 @@ |
635 | data=self.manufacturer)) |
636 | return |
637 | |
638 | - def process_inf2(self, data): |
639 | + def process_inf2(self, data, *args, **kwargs): |
640 | """ |
641 | Projector Model set in projector. |
642 | Updates self.model. |
643 | @@ -466,7 +440,7 @@ |
644 | log.debug('({ip}) Setting projector model to "{data}"'.format(ip=self.entry.name, data=self.model)) |
645 | return |
646 | |
647 | - def process_info(self, data): |
648 | + def process_info(self, data, *args, **kwargs): |
649 | """ |
650 | Any extra info set in projector. |
651 | Updates self.other_info. |
652 | @@ -477,7 +451,7 @@ |
653 | log.debug('({ip}) Setting projector other_info to "{data}"'.format(ip=self.entry.name, data=self.other_info)) |
654 | return |
655 | |
656 | - def process_inpt(self, data): |
657 | + def process_inpt(self, data, *args, **kwargs): |
658 | """ |
659 | Current source input selected. See PJLink specification for format. |
660 | Update self.source |
661 | @@ -499,7 +473,7 @@ |
662 | log.debug('({ip}) Setting data source to "{data}"'.format(ip=self.entry.name, data=self.source)) |
663 | return |
664 | |
665 | - def process_inst(self, data): |
666 | + def process_inst(self, data, *args, **kwargs): |
667 | """ |
668 | Available source inputs. See PJLink specification for format. |
669 | Updates self.source_available |
670 | @@ -516,7 +490,7 @@ |
671 | data=self.source_available)) |
672 | return |
673 | |
674 | - def process_lamp(self, data): |
675 | + def process_lamp(self, data, *args, **kwargs): |
676 | """ |
677 | Lamp(s) status. See PJLink Specifications for format. |
678 | Data may have more than 1 lamp to process. |
679 | @@ -542,7 +516,18 @@ |
680 | self.lamp = lamps |
681 | return |
682 | |
683 | - def process_name(self, data): |
684 | + def process_lkup(self, data, host, port): |
685 | + """ |
686 | + Process reply indicating remote is available for connection |
687 | + |
688 | + :param data: Data packet from remote |
689 | + :param host: Remote IP address |
690 | + :param port: Local port packet received on |
691 | + """ |
692 | + # TODO: Check if autoconnect is enabled and connect? |
693 | + pass |
694 | + |
695 | + def process_name(self, data, *args, **kwargs): |
696 | """ |
697 | Projector name set in projector. |
698 | Updates self.pjlink_name |
699 | @@ -553,7 +538,7 @@ |
700 | log.debug('({ip}) Setting projector PJLink name to "{data}"'.format(ip=self.entry.name, data=self.pjlink_name)) |
701 | return |
702 | |
703 | - def process_pjlink(self, data): |
704 | + def process_pjlink(self, data, *args, **kwargs): |
705 | """ |
706 | Process initial socket connection to terminal. |
707 | |
708 | @@ -594,7 +579,7 @@ |
709 | # Since this is an initial connection, make it a priority just in case |
710 | return self.send_command(cmd="CLSS", salt=data_hash, priority=True) |
711 | |
712 | - def process_powr(self, data): |
713 | + def process_powr(self, data, *args, **kwargs): |
714 | """ |
715 | Power status. See PJLink specification for format. |
716 | Update self.power with status. Update icons if change from previous setting. |
717 | @@ -617,7 +602,7 @@ |
718 | log.warning('({ip}) Unknown power response: "{data}"'.format(ip=self.entry.name, data=data)) |
719 | return |
720 | |
721 | - def process_rfil(self, data): |
722 | + def process_rfil(self, data, *args, **kwargs): |
723 | """ |
724 | Process replacement filter type |
725 | """ |
726 | @@ -628,7 +613,7 @@ |
727 | log.warning('({ip}) Saved model: "{old}"'.format(ip=self.entry.name, old=self.model_filter)) |
728 | log.warning('({ip}) New model: "{new}"'.format(ip=self.entry.name, new=data)) |
729 | |
730 | - def process_rlmp(self, data): |
731 | + def process_rlmp(self, data, *args, **kwargs): |
732 | """ |
733 | Process replacement lamp type |
734 | """ |
735 | @@ -639,7 +624,7 @@ |
736 | log.warning('({ip}) Saved lamp: "{old}"'.format(ip=self.entry.name, old=self.model_lamp)) |
737 | log.warning('({ip}) New lamp: "{new}"'.format(ip=self.entry.name, new=data)) |
738 | |
739 | - def process_snum(self, data): |
740 | + def process_snum(self, data, *args, **kwargs): |
741 | """ |
742 | Serial number of projector. |
743 | |
744 | @@ -659,7 +644,20 @@ |
745 | log.warning('({ip}) NOT saving serial number'.format(ip=self.entry.name)) |
746 | self.serial_no_received = data |
747 | |
748 | - def process_sver(self, data): |
749 | + def process_srch(self, data, host, port): |
750 | + """ |
751 | + Process the SRCH command. |
752 | + |
753 | + SRCH is processed by terminals so we ignore any packet. |
754 | + |
755 | + :param data: Data in packet |
756 | + :param host: IP address of sending host |
757 | + :param port: Port received on |
758 | + """ |
759 | + log.warning('(UDP) SRCH packet received from {host} - ignoring'.format(host=host)) |
760 | + return |
761 | + |
762 | + def process_sver(self, data, *args, **kwargs): |
763 | """ |
764 | Software version of projector |
765 | """ |
766 | @@ -716,6 +714,7 @@ |
767 | self.pin = self.entry.pin |
768 | self.port = self.entry.port |
769 | self.pjlink_class = PJLINK_CLASS if self.entry.pjlink_class is None else self.entry.pjlink_class |
770 | + self.ackn_list = {} # Replies from online projectors (Class 2 option) |
771 | self.db_update = False # Use to check if db needs to be updated prior to exiting |
772 | # Poll time 20 seconds unless called with something else |
773 | self.poll_time = 20000 if 'poll_time' not in kwargs else kwargs['poll_time'] * 1000 |
774 | @@ -916,7 +915,10 @@ |
775 | """ |
776 | Clean out extraneous stuff in the buffer. |
777 | """ |
778 | - log.warning('({ip}) {message}'.format(ip=self.entry.name, message='Invalid packet' if msg is None else msg)) |
779 | + log.debug('({ip}) Cleaning buffer - msg = "{message}"'.format(ip=self.entry.name, message=msg)) |
780 | + if msg is None: |
781 | + msg = 'Invalid packet' |
782 | + log.warning('({ip}) {message}'.format(ip=self.entry.name, message=msg)) |
783 | self.send_busy = False |
784 | trash_count = 0 |
785 | while self.bytesAvailable() > 0: |
786 | @@ -960,7 +962,7 @@ |
787 | self.socket_timer.stop() |
788 | return self.get_data(buff=read, ip=self.ip) |
789 | |
790 | - def get_data(self, buff, ip=None): |
791 | + def get_data(self, buff, ip=None, *args, **kwargs): |
792 | """ |
793 | Process received data |
794 | |
795 | @@ -973,45 +975,61 @@ |
796 | ip = self.ip |
797 | log.debug('({ip}) get_data(ip="{ip_in}" buffer="{buff}"'.format(ip=self.entry.name, ip_in=ip, buff=buff)) |
798 | # NOTE: Class2 has changed to some values being UTF-8 |
799 | - data_in = decode(buff, 'utf-8') |
800 | + if isinstance(buff, bytes): |
801 | + data_in = decode(buff, 'utf-8') |
802 | + else: |
803 | + data_in = buff |
804 | data = data_in.strip() |
805 | # Initial packet checks |
806 | if (len(data) < 7): |
807 | self._trash_buffer(msg='get_data(): Invalid packet - length') |
808 | return self.receive_data_signal() |
809 | elif len(data) > self.max_size: |
810 | - self._trash_buffer(msg='get_data(): Invalid packet - too long') |
811 | + self._trash_buffer(msg='get_data(): Invalid packet - too long ({length} bytes)'.format(length=len(data))) |
812 | return self.receive_data_signal() |
813 | elif not data.startswith(PJLINK_PREFIX): |
814 | self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing') |
815 | return self.receive_data_signal() |
816 | - elif '=' not in data: |
817 | + elif data[6] != '=': |
818 | self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="') |
819 | return self.receive_data_signal() |
820 | log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.entry.name, data=data)) |
821 | header, data = data.split('=') |
822 | + log.debug('({ip}) get_data() header="{header}" data="{data}"'.format(ip=self.entry.name, |
823 | + header=header, data=data)) |
824 | # At this point, the header should contain: |
825 | # "PVCCCC" |
826 | # Where: |
827 | # P = PJLINK_PREFIX |
828 | # V = PJLink class or version |
829 | # C = PJLink command |
830 | + version, cmd = header[1], header[2:].upper() |
831 | + log.debug('({ip}) get_data() version="{version}" cmd="{cmd}"'.format(ip=self.entry.name, |
832 | + version=version, cmd=cmd)) |
833 | + # TODO: Below commented for now since it seems to cause issues with testing some invalid data. |
834 | + # Revisit after more refactoring is finished. |
835 | + ''' |
836 | try: |
837 | version, cmd = header[1], header[2:].upper() |
838 | + log.debug('({ip}) get_data() version="{version}" cmd="{cmd}"'.format(ip=self.entry.name, |
839 | + version=version, cmd=cmd)) |
840 | except ValueError as e: |
841 | self.change_status(E_INVALID_DATA) |
842 | log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.entry.name, data=data_in)) |
843 | self._trash_buffer('get_data(): Expected header + command + data') |
844 | return self.receive_data_signal() |
845 | + ''' |
846 | if cmd not in PJLINK_VALID_CMD: |
847 | - log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.entry.name, |
848 | + self._trash_buffer('get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.entry.name, |
849 | data=cmd)) |
850 | - self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd)) |
851 | - return self.receive_data_signal() |
852 | - if int(self.pjlink_class) < int(version): |
853 | + return self.receive_data_signal() |
854 | + elif version not in PJLINK_VALID_CMD[cmd]['version']: |
855 | + self._trash_buffer(msg='get_data() Command reply version does not match a valid command version') |
856 | + return self.receive_data_signal() |
857 | + elif int(self.pjlink_class) < int(version): |
858 | log.warning('({ip}) get_data(): Projector returned class reply higher ' |
859 | 'than projector stated class'.format(ip=self.entry.name)) |
860 | - self.process_command(cmd, data) |
861 | + self.process_command(cmd, data, *args, **kwargs) |
862 | return self.receive_data_signal() |
863 | |
864 | @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError) |
865 | @@ -1063,16 +1081,7 @@ |
866 | data=opts, |
867 | salt='' if salt is None |
868 | else ' with hash')) |
869 | - cmd_ver = PJLINK_VALID_CMD[cmd]['version'] |
870 | - if self.pjlink_class in PJLINK_VALID_CMD[cmd]['version']: |
871 | - header = PJLINK_HEADER.format(linkclass=self.pjlink_class) |
872 | - elif len(cmd_ver) == 1 and (int(cmd_ver[0]) < int(self.pjlink_class)): |
873 | - # Typically a class 1 only command |
874 | - header = PJLINK_HEADER.format(linkclass=cmd_ver[0]) |
875 | - else: |
876 | - # NOTE: Once we get to version 3 then think about looping |
877 | - log.error('({ip}): send_command(): PJLink class check issue? Aborting'.format(ip=self.entry.name)) |
878 | - return |
879 | + header = PJLINK_HEADER.format(linkclass=self.pjlink_functions[cmd]["version"]) |
880 | out = '{salt}{header}{command} {options}{suffix}'.format(salt="" if salt is None else salt, |
881 | header=header, |
882 | command=cmd, |
883 | |
884 | === modified file 'tests/openlp_core/projectors/test_projector_db.py' |
885 | --- tests/openlp_core/projectors/test_projector_db.py 2018-01-13 05:41:42 +0000 |
886 | +++ tests/openlp_core/projectors/test_projector_db.py 2018-04-20 06:05:02 +0000 |
887 | @@ -29,12 +29,15 @@ |
888 | import shutil |
889 | from tempfile import mkdtemp |
890 | from unittest import TestCase |
891 | -from unittest.mock import patch |
892 | +from unittest.mock import MagicMock, patch |
893 | |
894 | +from openlp.core.common.registry import Registry |
895 | from openlp.core.lib.db import upgrade_db |
896 | from openlp.core.projectors import upgrade |
897 | from openlp.core.projectors.constants import PJLINK_PORT |
898 | from openlp.core.projectors.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource, Source |
899 | +from openlp.core.ui.mainwindow import MainWindow |
900 | +from tests.helpers.testmixin import TestMixin |
901 | from tests.resources.projector.data import TEST_DB_PJLINK1, TEST_DB, TEST1_DATA, TEST2_DATA, TEST3_DATA |
902 | from tests.utils.constants import TEST_RESOURCES_PATH |
903 | |
904 | @@ -122,7 +125,7 @@ |
905 | assert updated_to_version == latest_version, 'The projector DB should have been upgrade to the latest version' |
906 | |
907 | |
908 | -class TestProjectorDB(TestCase): |
909 | +class TestProjectorDB(TestCase, TestMixin): |
910 | """ |
911 | Test case for ProjectorDB |
912 | """ |
913 | @@ -131,6 +134,33 @@ |
914 | """ |
915 | Set up anything necessary for all tests |
916 | """ |
917 | + # Create a test app to keep from segfaulting |
918 | + Registry.create() |
919 | + self.registry = Registry() |
920 | + self.setup_application() |
921 | + # Mock cursor busy/normal methods. |
922 | + self.app.set_busy_cursor = MagicMock() |
923 | + self.app.set_normal_cursor = MagicMock() |
924 | + self.app.args = [] |
925 | + Registry().register('application', self.app) |
926 | + Registry().set_flag('no_web_server', True) |
927 | + # Mock classes and methods used by mainwindow. |
928 | + with patch('openlp.core.ui.mainwindow.SettingsForm'), \ |
929 | + patch('openlp.core.ui.mainwindow.ImageManager'), \ |
930 | + patch('openlp.core.ui.mainwindow.LiveController'), \ |
931 | + patch('openlp.core.ui.mainwindow.PreviewController'), \ |
932 | + patch('openlp.core.ui.mainwindow.OpenLPDockWidget'), \ |
933 | + patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox'), \ |
934 | + patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget'), \ |
935 | + patch('openlp.core.ui.mainwindow.ServiceManager'), \ |
936 | + patch('openlp.core.ui.mainwindow.ThemeManager'), \ |
937 | + patch('openlp.core.ui.mainwindow.ProjectorManager'), \ |
938 | + patch('openlp.core.ui.mainwindow.Renderer'), \ |
939 | + patch('openlp.core.ui.mainwindow.websockets.WebSocketServer'), \ |
940 | + patch('openlp.core.ui.mainwindow.server.HttpServer'): |
941 | + self.main_window = MainWindow() |
942 | + |
943 | + # Create a temporary database directory and database |
944 | self.tmp_folder = mkdtemp(prefix='openlp_') |
945 | tmpdb_url = 'sqlite:///{db}'.format(db=os.path.join(self.tmp_folder, TEST_DB)) |
946 | mocked_init_url.return_value = tmpdb_url |
947 | @@ -139,9 +169,12 @@ |
948 | def tearDown(self): |
949 | """ |
950 | Clean up |
951 | + |
952 | + Delete all the C++ objects at the end so that we don't have a segfault |
953 | """ |
954 | self.projector.session.close() |
955 | self.projector = None |
956 | + del self.main_window |
957 | # Ignore errors since windows can have problems with locked files |
958 | shutil.rmtree(self.tmp_folder, ignore_errors=True) |
959 | |
960 | |
961 | === renamed file 'tests/openlp_core/projectors/test_projectoreditform.py' => 'tests/openlp_core/projectors/test_projector_editform.py' |
962 | === modified file 'tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py' |
963 | --- tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2018-01-13 05:41:42 +0000 |
964 | +++ tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2018-04-20 06:05:02 +0000 |
965 | @@ -39,30 +39,31 @@ |
966 | """ |
967 | Tests for the PJLink module command routing |
968 | """ |
969 | - def test_get_data_unknown_command(self): |
970 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
971 | + def test_get_data_unknown_command(self, mock_log): |
972 | """ |
973 | Test not a valid command |
974 | """ |
975 | # GIVEN: Test object |
976 | - with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \ |
977 | - patch.object(openlp.core.projectors.pjlink.PJLink, '_trash_buffer') as mock_buffer: |
978 | - |
979 | - pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True) |
980 | - pjlink.pjlink_functions = MagicMock() |
981 | - log_warning_text = [call('({ip}) get_data(): Invalid packet - ' |
982 | - 'unknown command "UNK"'.format(ip=pjlink.name))] |
983 | - log_debug_text = [call('({ip}) get_data(ip="111.111.111.111" ' |
984 | - 'buffer="b\'%1UNK=Huh?\'"'.format(ip=pjlink.name)), |
985 | - call('({ip}) get_data(): Checking new data "%1UNK=Huh?"'.format(ip=pjlink.name))] |
986 | - |
987 | - # WHEN: get_data called with an unknown command |
988 | - pjlink.get_data(buff='{prefix}1UNK=Huh?'.format(prefix=PJLINK_PREFIX).encode('utf-8')) |
989 | - |
990 | - # THEN: Appropriate log entries should have been made and methods called/not called |
991 | - mock_log.debug.assert_has_calls(log_debug_text) |
992 | - mock_log.warning.assert_has_calls(log_warning_text) |
993 | - assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions' |
994 | - assert mock_buffer.called is True, 'Should have called _trash_buffer' |
995 | + pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True) |
996 | + pjlink.pjlink_functions = MagicMock() |
997 | + log_warning_text = [call('({ip}) get_data(): Invalid packet - ' |
998 | + 'unknown command "UNKN"'.format(ip=pjlink.name))] |
999 | + log_debug_text = [call('(___TEST_ONE___) get_data(ip="111.111.111.111" buffer="%1UNKN=Huh?"'), |
1000 | + call('(___TEST_ONE___) get_data(): Checking new data "%1UNKN=Huh?"'), |
1001 | + call('(___TEST_ONE___) get_data() header="%1UNKN" data="Huh?"'), |
1002 | + call('(___TEST_ONE___) get_data() version="1" cmd="UNKN"'), |
1003 | + call('(___TEST_ONE___) Cleaning buffer - msg = "get_data(): ' |
1004 | + 'Invalid packet - unknown command "UNKN""'), |
1005 | + call('(___TEST_ONE___) Finished cleaning buffer - 0 bytes dropped')] |
1006 | + |
1007 | + # WHEN: get_data called with an unknown command |
1008 | + pjlink.get_data(buff='{prefix}1UNKN=Huh?'.format(prefix=PJLINK_PREFIX)) |
1009 | + |
1010 | + # THEN: Appropriate log entries should have been made and methods called/not called |
1011 | + mock_log.warning.assert_has_calls(log_warning_text) |
1012 | + mock_log.debug.assert_has_calls(log_debug_text) |
1013 | + assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions' |
1014 | |
1015 | def test_process_command_call_clss(self): |
1016 | """ |
1017 | @@ -219,7 +220,6 @@ |
1018 | """ |
1019 | Test command returned success |
1020 | """ |
1021 | - # GIVEN: Initial mocks and data |
1022 | # GIVEN: Test object and mocks |
1023 | with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \ |
1024 | patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \ |
1025 | |
1026 | === modified file 'tests/openlp_core/projectors/test_projector_pjlink_commands_02.py' |
1027 | --- tests/openlp_core/projectors/test_projector_pjlink_commands_02.py 2018-01-13 05:41:42 +0000 |
1028 | +++ tests/openlp_core/projectors/test_projector_pjlink_commands_02.py 2018-04-20 06:05:02 +0000 |
1029 | @@ -22,14 +22,14 @@ |
1030 | """ |
1031 | Package to test the openlp.core.projectors.pjlink commands package. |
1032 | """ |
1033 | -from unittest import TestCase |
1034 | +from unittest import TestCase, skip |
1035 | from unittest.mock import patch, call |
1036 | |
1037 | import openlp.core.projectors.pjlink |
1038 | -from openlp.core.projectors.constants import S_CONNECTED, S_OFF, S_ON |
1039 | +from openlp.core.projectors.constants import PJLINK_PORT, S_CONNECTED, S_OFF, S_ON |
1040 | from openlp.core.projectors.db import Projector |
1041 | -from openlp.core.projectors.pjlink import PJLink |
1042 | -from tests.resources.projector.data import TEST_HASH, TEST_PIN, TEST_SALT, TEST1_DATA |
1043 | +from openlp.core.projectors.pjlink import PJLink, PJLinkUDP |
1044 | +from tests.resources.projector.data import TEST_HASH, TEST_PIN, TEST_SALT, TEST1_DATA, TEST2_DATA |
1045 | |
1046 | |
1047 | class TestPJLinkCommands(TestCase): |
1048 | @@ -235,3 +235,114 @@ |
1049 | mock_log.error.assert_has_calls(log_check) |
1050 | assert 1 == mock_disconnect_from_host.call_count, 'Should have only been called once' |
1051 | mock_send_command.assert_not_called() |
1052 | + |
1053 | + @skip('Change to pjlink_udp.get_datagram() call') |
1054 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
1055 | + def test_process_ackn_duplicate(self, mock_log): |
1056 | + """ |
1057 | + Test process_ackn method with multiple calls with same data |
1058 | + """ |
1059 | + # TODO: Change this to call pjlink_udp.get_datagram() so ACKN can be processed properly |
1060 | + |
1061 | + # GIVEN: Test setup |
1062 | + pjlink = PJLink(projector=self.test_list[0]) |
1063 | + check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}} |
1064 | + log_warn_calls = [call('(___TEST_ONE___) Host {host} already replied - ' |
1065 | + 'ignoring'.format(host=TEST1_DATA['ip']))] |
1066 | + log_debug_calls = [call('PJlinkCommands(args=() kwargs={})'), |
1067 | + call('(___TEST_ONE___) reset_information() connect status is S_NOT_CONNECTED'), |
1068 | + call('(___TEST_ONE___) Processing ACKN packet'), |
1069 | + call('(___TEST_ONE___) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip'])), |
1070 | + call('(___TEST_ONE___) Processing ACKN packet')] |
1071 | + |
1072 | + # WHEN: process_ackn called twice with same data |
1073 | + pjlink.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1074 | + pjlink.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1075 | + |
1076 | + # THEN: pjlink_udp.ack_list should equal test_list |
1077 | + # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? |
1078 | + if pjlink.ackn_list != check_list: |
1079 | + # Check this way so we can print differences to stdout |
1080 | + print('\nackn_list: ', pjlink.ackn_list) |
1081 | + print('test_list: ', check_list, '\n') |
1082 | + assert pjlink.ackn_list == check_list |
1083 | + mock_log.debug.assert_has_calls(log_debug_calls) |
1084 | + mock_log.warning.assert_has_calls(log_warn_calls) |
1085 | + |
1086 | + @skip('Change to pjlink_udp.get_datagram() call') |
1087 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
1088 | + def test_process_ackn_multiple(self, mock_log): |
1089 | + """ |
1090 | + Test process_ackn method with multiple calls |
1091 | + """ |
1092 | + # TODO: Change this to call pjlink_udp.get_datagram() so ACKN can be processed properly |
1093 | + |
1094 | + # GIVEN: Test setup |
1095 | + pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1096 | + check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}, |
1097 | + TEST2_DATA['ip']: {'data': TEST2_DATA['mac_adx'], 'port': PJLINK_PORT}} |
1098 | + log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1099 | + call('(UDP) Processing ACKN packet'), |
1100 | + call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip'])), |
1101 | + call('(UDP) Processing ACKN packet'), |
1102 | + call('(UDP) Adding {host} to ACKN list'.format(host=TEST2_DATA['ip']))] |
1103 | + |
1104 | + # WHEN: process_ackn called twice with different data |
1105 | + pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1106 | + pjlink_udp.process_ackn(data=TEST2_DATA['mac_adx'], host=TEST2_DATA['ip'], port=PJLINK_PORT) |
1107 | + |
1108 | + # THEN: pjlink_udp.ack_list should equal test_list |
1109 | + # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? |
1110 | + if pjlink_udp.ackn_list != check_list: |
1111 | + # Check this way so we can print differences to stdout |
1112 | + print('\nackn_list: ', pjlink_udp.ackn_list) |
1113 | + print('test_list: ', check_list) |
1114 | + assert pjlink_udp.ackn_list == check_list |
1115 | + mock_log.debug.assert_has_calls(log_debug_calls) |
1116 | + |
1117 | + @skip('Change to pjlink_udp.get_datagram() call') |
1118 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
1119 | + def test_process_ackn_single(self, mock_log): |
1120 | + """ |
1121 | + Test process_ackn method with single call |
1122 | + """ |
1123 | + # TODO: Change this to call pjlink_udp.get_datagram() so ACKN can be processed properly |
1124 | + |
1125 | + # GIVEN: Test setup |
1126 | + pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1127 | + check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}} |
1128 | + log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1129 | + call('(UDP) Processing ACKN packet'), |
1130 | + call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip']))] |
1131 | + |
1132 | + # WHEN: process_ackn called twice with different data |
1133 | + pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1134 | + |
1135 | + # THEN: pjlink_udp.ack_list should equal test_list |
1136 | + # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? |
1137 | + if pjlink_udp.ackn_list != check_list: |
1138 | + # Check this way so we can print differences to stdout |
1139 | + print('\nackn_list: ', pjlink_udp.ackn_list) |
1140 | + print('test_list: ', check_list) |
1141 | + assert pjlink_udp.ackn_list == check_list |
1142 | + mock_log.debug.assert_has_calls(log_debug_calls) |
1143 | + |
1144 | + @skip('Change to pjlink_udp.get_datagram() call') |
1145 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
1146 | + def test_process_srch(self, mock_log): |
1147 | + """ |
1148 | + Test process_srch method |
1149 | + """ |
1150 | + # TODO: Change this to call pjlink_udp.get_datagram() so ACKN can be processed properly |
1151 | + |
1152 | + # GIVEN: Test setup |
1153 | + log_warn_calls = [call('(UDP) SRCH packet received from {ip} - ignoring'.format(ip=TEST1_DATA['ip'])), ] |
1154 | + log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), ] |
1155 | + pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1156 | + |
1157 | + # WHEN: process_srch called |
1158 | + pjlink_udp.process_srch(data=None, host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1159 | + |
1160 | + # THEN: log entries should be entered |
1161 | + mock_log.warning.assert_has_calls(log_warn_calls) |
1162 | + mock_log.debug.assert_has_calls(log_debug_calls) |
1163 | |
1164 | === modified file 'tests/openlp_core/projectors/test_projector_pjlink_udp.py' |
1165 | --- tests/openlp_core/projectors/test_projector_pjlink_udp.py 2018-02-11 11:42:13 +0000 |
1166 | +++ tests/openlp_core/projectors/test_projector_pjlink_udp.py 2018-04-20 06:05:02 +0000 |
1167 | @@ -28,10 +28,10 @@ |
1168 | from unittest.mock import call, patch |
1169 | |
1170 | import openlp.core.projectors.pjlink |
1171 | -from openlp.core.projectors.constants import PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_PREFIX |
1172 | +from openlp.core.projectors.constants import PJLINK_PORT |
1173 | |
1174 | from openlp.core.projectors.db import Projector |
1175 | -from openlp.core.projectors.pjlink import PJLinkUDP |
1176 | +from openlp.core.projectors.pjlink import PJLinkUDP, PJLink |
1177 | from tests.resources.projector.data import TEST1_DATA, TEST2_DATA |
1178 | |
1179 | |
1180 | @@ -43,7 +43,8 @@ |
1181 | """ |
1182 | Setup generic test conditions |
1183 | """ |
1184 | - self.test_list = [Projector(**TEST1_DATA), Projector(**TEST2_DATA)] |
1185 | + self.test_list = [PJLink(projector=Projector(**TEST1_DATA)), |
1186 | + PJLink(projector=Projector(**TEST2_DATA))] |
1187 | |
1188 | def tearDown(self): |
1189 | """ |
1190 | @@ -52,132 +53,6 @@ |
1191 | self.test_list = None |
1192 | |
1193 | @patch.object(openlp.core.projectors.pjlink, 'log') |
1194 | - def test_get_datagram_data_invalid_class(self, mock_log): |
1195 | - """ |
1196 | - Test get_datagram with invalid class number |
1197 | - """ |
1198 | - # GIVEN: Test setup |
1199 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1200 | - log_warn_calls = [call('(UDP) Invalid packet - missing/invalid PJLink class version')] |
1201 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1202 | - call('(UDP) get_datagram() - Receiving data'), |
1203 | - call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), |
1204 | - call('(UDP) packet "%1ACKN=11:11:11:11:11:11"')] |
1205 | - with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1206 | - patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1207 | - mock_datagram.return_value = 24 |
1208 | - mock_read.return_value = ('{prefix}1ACKN={mac}'.format(prefix=PJLINK_PREFIX, mac=TEST1_DATA['mac_adx']), |
1209 | - TEST1_DATA['ip'], PJLINK_PORT) |
1210 | - |
1211 | - # WHEN: get_datagram called with 0 bytes ready |
1212 | - pjlink_udp.get_datagram() |
1213 | - |
1214 | - # THEN: Log entries should be made and method returns |
1215 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1216 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1217 | - |
1218 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1219 | - def test_get_datagram_data_invalid_command(self, mock_log): |
1220 | - """ |
1221 | - Test get_datagram with invalid PJLink UDP command |
1222 | - """ |
1223 | - # GIVEN: Test setup |
1224 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1225 | - log_warn_calls = [call('(UDP) Invalid packet - not a valid PJLink UDP reply')] |
1226 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1227 | - call('(UDP) get_datagram() - Receiving data'), |
1228 | - call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), |
1229 | - call('(UDP) packet "%2DUMB=11:11:11:11:11:11"')] |
1230 | - with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1231 | - patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1232 | - mock_datagram.return_value = 24 |
1233 | - mock_read.return_value = ('{prefix}2DUMB={mac}'.format(prefix=PJLINK_PREFIX, mac=TEST1_DATA['mac_adx']), |
1234 | - TEST1_DATA['ip'], PJLINK_PORT) |
1235 | - |
1236 | - # WHEN: get_datagram called with 0 bytes ready |
1237 | - pjlink_udp.get_datagram() |
1238 | - |
1239 | - # THEN: Log entries should be made and method returns |
1240 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1241 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1242 | - |
1243 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1244 | - def test_get_datagram_data_invalid_prefix(self, mock_log): |
1245 | - """ |
1246 | - Test get_datagram when prefix != PJLINK_PREFIX |
1247 | - """ |
1248 | - # GIVEN: Test setup |
1249 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1250 | - log_warn_calls = [call('(UDP) Invalid packet - does not start with PJLINK_PREFIX')] |
1251 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1252 | - call('(UDP) get_datagram() - Receiving data'), |
1253 | - call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), |
1254 | - call('(UDP) packet "$2ACKN=11:11:11:11:11:11"')] |
1255 | - with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1256 | - patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1257 | - mock_datagram.return_value = 24 |
1258 | - mock_read.return_value = ('{prefix}2ACKN={mac}'.format(prefix='$', mac=TEST1_DATA['mac_adx']), |
1259 | - TEST1_DATA['ip'], PJLINK_PORT) |
1260 | - |
1261 | - # WHEN: get_datagram called with 0 bytes ready |
1262 | - pjlink_udp.get_datagram() |
1263 | - |
1264 | - # THEN: Log entries should be made and method returns |
1265 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1266 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1267 | - |
1268 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1269 | - def test_get_datagram_data_invalid_separator(self, mock_log): |
1270 | - """ |
1271 | - Test get_datagram when separator not equal to = |
1272 | - """ |
1273 | - # GIVEN: Test setup |
1274 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1275 | - log_warn_calls = [call('(UDP) Invalid packet - separator missing')] |
1276 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1277 | - call('(UDP) get_datagram() - Receiving data'), |
1278 | - call('(UDP) 24 bytes received from 111.111.111.111 on port 4352'), |
1279 | - call('(UDP) packet "%2ACKN 11:11:11:11:11:11"')] |
1280 | - with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1281 | - patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1282 | - mock_datagram.return_value = 24 |
1283 | - mock_read.return_value = ('{prefix}2ACKN {mac}'.format(prefix=PJLINK_PREFIX, mac=TEST1_DATA['mac_adx']), |
1284 | - TEST1_DATA['ip'], PJLINK_PORT) |
1285 | - |
1286 | - # WHEN: get_datagram called with 0 bytes ready |
1287 | - pjlink_udp.get_datagram() |
1288 | - |
1289 | - # THEN: Log entries should be made and method returns |
1290 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1291 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1292 | - |
1293 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1294 | - def test_get_datagram_data_long(self, mock_log): |
1295 | - """ |
1296 | - Test get_datagram when datagram > PJLINK_MAX_PACKET |
1297 | - """ |
1298 | - # GIVEN: Test setup |
1299 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1300 | - log_warn_calls = [call('(UDP) Invalid packet - length too long')] |
1301 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1302 | - call('(UDP) get_datagram() - Receiving data'), |
1303 | - call('(UDP) 143 bytes received from 111.111.111.111 on port 4352'), |
1304 | - call('(UDP) packet "%2ACKN={long}"'.format(long='X' * PJLINK_MAX_PACKET))] |
1305 | - with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1306 | - patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1307 | - mock_datagram.return_value = PJLINK_MAX_PACKET + 7 |
1308 | - mock_read.return_value = ('{prefix}2ACKN={long}'.format(prefix=PJLINK_PREFIX, |
1309 | - long='X' * PJLINK_MAX_PACKET), |
1310 | - TEST1_DATA['ip'], PJLINK_PORT) |
1311 | - |
1312 | - # WHEN: get_datagram called with 0 bytes ready |
1313 | - pjlink_udp.get_datagram() |
1314 | - |
1315 | - # THEN: Log entries should be made and method returns |
1316 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1317 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1318 | - |
1319 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1320 | def test_get_datagram_data_negative_zero_length(self, mock_log): |
1321 | """ |
1322 | Test get_datagram when pendingDatagramSize = 0 |
1323 | @@ -196,7 +71,7 @@ |
1324 | pjlink_udp.get_datagram() |
1325 | |
1326 | # THEN: Log entries should be made and method returns |
1327 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1328 | + mock_log.warning.assert_has_calls(log_warn_calls) |
1329 | mock_log.debug.assert_has_calls(log_debug_calls) |
1330 | |
1331 | @patch.object(openlp.core.projectors.pjlink, 'log') |
1332 | @@ -206,41 +81,18 @@ |
1333 | """ |
1334 | # GIVEN: Test setup |
1335 | pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1336 | - log_warn_calls = [call('(UDP) Invalid packet - not enough data')] |
1337 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1338 | - call('(UDP) get_datagram() - Receiving data')] |
1339 | + log_warn_calls = [call('(UDP) get_datagram() called when pending data size is 0')] |
1340 | + log_debug_calls = [call('(UDP) get_datagram() - Receiving data')] |
1341 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1342 | patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1343 | - mock_datagram.return_value = 1 |
1344 | + mock_datagram.return_value = 0 |
1345 | mock_read.return_value = ('', TEST1_DATA['ip'], PJLINK_PORT) |
1346 | |
1347 | # WHEN: get_datagram called with 0 bytes ready |
1348 | pjlink_udp.get_datagram() |
1349 | |
1350 | # THEN: Log entries should be made and method returns |
1351 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1352 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1353 | - |
1354 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1355 | - def test_get_datagram_data_short(self, mock_log): |
1356 | - """ |
1357 | - Test get_datagram when data length < 8 |
1358 | - """ |
1359 | - # GIVEN: Test setup |
1360 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1361 | - log_warn_calls = [call('(UDP) Invalid packet - not enough data')] |
1362 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1363 | - call('(UDP) get_datagram() - Receiving data')] |
1364 | - with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
1365 | - patch.object(pjlink_udp, 'readDatagram') as mock_read: |
1366 | - mock_datagram.return_value = 6 |
1367 | - mock_read.return_value = ('{prefix}2ACKN'.format(prefix=PJLINK_PREFIX), TEST1_DATA['ip'], PJLINK_PORT) |
1368 | - |
1369 | - # WHEN: get_datagram called with 0 bytes ready |
1370 | - pjlink_udp.get_datagram() |
1371 | - |
1372 | - # THEN: Log entries should be made and method returns |
1373 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1374 | + mock_log.warning.assert_has_calls(log_warn_calls) |
1375 | mock_log.debug.assert_has_calls(log_debug_calls) |
1376 | |
1377 | @patch.object(openlp.core.projectors.pjlink, 'log') |
1378 | @@ -260,101 +112,5 @@ |
1379 | pjlink_udp.get_datagram() |
1380 | |
1381 | # THEN: Log entries should be made and method returns |
1382 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1383 | + mock_log.warning.assert_has_calls(log_warn_calls) |
1384 | mock_log.debug.assert_has_calls(log_debug_calls) |
1385 | - |
1386 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1387 | - def test_process_ackn_duplicate(self, mock_log): |
1388 | - """ |
1389 | - Test process_ackn method with multiple calls with same data |
1390 | - """ |
1391 | - # GIVEN: Test setup |
1392 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1393 | - check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}} |
1394 | - log_warn_calls = [call('(UDP) Host {host} already replied - ignoring'.format(host=TEST1_DATA['ip']))] |
1395 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1396 | - call('(UDP) Processing ACKN packet'), |
1397 | - call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip'])), |
1398 | - call('(UDP) Processing ACKN packet')] |
1399 | - |
1400 | - # WHEN: process_ackn called twice with same data |
1401 | - pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1402 | - pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1403 | - |
1404 | - # THEN: pjlink_udp.ack_list should equal test_list |
1405 | - # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? |
1406 | - if pjlink_udp.ackn_list != check_list: |
1407 | - # Check this way so we can print differences to stdout |
1408 | - print('\nackn_list: ', pjlink_udp.ackn_list) |
1409 | - print('test_list: ', check_list) |
1410 | - assert pjlink_udp.ackn_list == check_list |
1411 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1412 | - mock_log.warn.assert_has_calls(log_warn_calls) |
1413 | - |
1414 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1415 | - def test_process_ackn_multiple(self, mock_log): |
1416 | - """ |
1417 | - Test process_ackn method with multiple calls |
1418 | - """ |
1419 | - # GIVEN: Test setup |
1420 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1421 | - check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}, |
1422 | - TEST2_DATA['ip']: {'data': TEST2_DATA['mac_adx'], 'port': PJLINK_PORT}} |
1423 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1424 | - call('(UDP) Processing ACKN packet'), |
1425 | - call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip'])), |
1426 | - call('(UDP) Processing ACKN packet'), |
1427 | - call('(UDP) Adding {host} to ACKN list'.format(host=TEST2_DATA['ip']))] |
1428 | - |
1429 | - # WHEN: process_ackn called twice with different data |
1430 | - pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1431 | - pjlink_udp.process_ackn(data=TEST2_DATA['mac_adx'], host=TEST2_DATA['ip'], port=PJLINK_PORT) |
1432 | - |
1433 | - # THEN: pjlink_udp.ack_list should equal test_list |
1434 | - # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? |
1435 | - if pjlink_udp.ackn_list != check_list: |
1436 | - # Check this way so we can print differences to stdout |
1437 | - print('\nackn_list: ', pjlink_udp.ackn_list) |
1438 | - print('test_list: ', check_list) |
1439 | - assert pjlink_udp.ackn_list == check_list |
1440 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1441 | - |
1442 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1443 | - def test_process_ackn_single(self, mock_log): |
1444 | - """ |
1445 | - Test process_ackn method with single call |
1446 | - """ |
1447 | - # GIVEN: Test setup |
1448 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1449 | - check_list = {TEST1_DATA['ip']: {'data': TEST1_DATA['mac_adx'], 'port': PJLINK_PORT}} |
1450 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1451 | - call('(UDP) Processing ACKN packet'), |
1452 | - call('(UDP) Adding {host} to ACKN list'.format(host=TEST1_DATA['ip']))] |
1453 | - |
1454 | - # WHEN: process_ackn called twice with different data |
1455 | - pjlink_udp.process_ackn(data=TEST1_DATA['mac_adx'], host=TEST1_DATA['ip'], port=PJLINK_PORT) |
1456 | - |
1457 | - # THEN: pjlink_udp.ack_list should equal test_list |
1458 | - # NOTE: This assert only returns AssertionError - does not list differences. Maybe add a compare function? |
1459 | - if pjlink_udp.ackn_list != check_list: |
1460 | - # Check this way so we can print differences to stdout |
1461 | - print('\nackn_list: ', pjlink_udp.ackn_list) |
1462 | - print('test_list: ', check_list) |
1463 | - assert pjlink_udp.ackn_list == check_list |
1464 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1465 | - |
1466 | - @patch.object(openlp.core.projectors.pjlink, 'log') |
1467 | - def test_process_srch(self, mock_log): |
1468 | - """ |
1469 | - Test process_srch method |
1470 | - """ |
1471 | - # GIVEN: Test setup |
1472 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
1473 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
1474 | - call('(UDP) SRCH packet received - ignoring')] |
1475 | - |
1476 | - # WHEN: process_srch called |
1477 | - pjlink_udp.process_srch(data=None, host=None, port=None) |
1478 | - |
1479 | - # THEN: debug log entry should be entered |
1480 | - mock_log.debug.assert_has_calls(log_debug_calls) |
1481 | |
1482 | === renamed file 'tests/openlp_core/projectors/test_projectorsourceform.py' => 'tests/openlp_core/projectors/test_projector_sourceform.py' |
Sorry will clash with one of my fixes which has been merged
See question