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