Merge lp:~alisonken1/openlp/pjlink2-r into lp:openlp
- pjlink2-r
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~alisonken1/openlp/pjlink2-r |
Merge into: | lp:openlp |
Diff against target: |
856 lines (+259/-133) 8 files modified
openlp/core/common/settings.py (+1/-0) openlp/core/projectors/manager.py (+25/-2) openlp/core/projectors/pjlink.py (+93/-87) openlp/core/projectors/tab.py (+8/-0) tests/openlp_core/projectors/test_projector_pjlink_base_01.py (+2/-12) tests/openlp_core/projectors/test_projector_pjlink_base_02.py (+101/-0) tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py (+14/-4) tests/openlp_core/projectors/test_projector_pjlink_udp.py (+15/-28) |
To merge this branch: | bzr merge lp:~alisonken1/openlp/pjlink2-r |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Phill | Needs Fixing | ||
Tim Bentley | Pending | ||
Review via email:
|
This proposal supersedes a proposal from 2018-04-28.
This proposal has been superseded by a proposal from 2018-05-03.
Commit message
PJLink2 update R
Description of the change
- Convert UDP packet to send pyqtSignal and let individual projectors decide who it's for
- Remove unneccessary *args **kwargs from commands
- Remove projector_list and projector block search since switching to signals
- pass on ACKN, and SRCH commands until I think about it some more
- Cleanup extraneous args on process_* commands since switching to signals
- Add UDP socket listener(s) for PJLink2 UDP options
- Added process_lkup method code
- Add projector configure option to connect when LKUP packet received
- Fix _send_queue to ignore call if no data to send
- Rename tests/openlp_
- Added tests/openlp_
- Added test for PJLink.
- Removed unused test_projector_
- Cleanup tests/openlp_
- Fix test_projector_
- Fix invalid delete projector signal disconnect call in manager
- Move try block under if block when disconnecting signal from deleted projector in manager
- Minor cleanups
-------
lp:~alisonken1/openlp/pjlink2-r (revision 2819)
https:/
https:/
https:/
https:/
https:/
https:/
https:/
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Phill (phill-ridout) wrote : Posted in a previous version of this proposal | # |
Ran out of time to complete a review, but a few in lines to start.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ken Roberts (alisonken1) wrote : Posted in a previous version of this proposal | # |
On Sat, Apr 28, 2018 at 12:15 AM, Phill <email address hidden> wrote:
> Review: Needs Fixing
>
> Ran out of time to complete a review, but a few in lines to start.
>
> Diff comments:
>
>>
>> === modified file 'openlp/
>> --- openlp/
>> +++ openlp/
>> if read_size < 0:
>> log.warning('(UDP) No data (-1)')
>> return
>> - if read_size < 1:
>> + elif read_size < 1:
>
> given the < 0 condition above, this condition will only be True when read_size == 0, which to me is a bit readable / obvious at a quick glance.
-1 indicates a socket problem - which is distinct from no data (0 or
empty packet)
>> @@ -654,10 +651,10 @@
>> :param host: IP address of sending host
>> :param port: Port received on
>> """
>> - log.warning('(UDP) SRCH packet received from {host} - ignoring'
>> + log.warning("({ip}) I don't do SRCH packets - ignoring"
>
> Why this change? the original is more understandable to me!
This method is only called from within a projector instance - not the
UDP monitor.
However, just noticed it's using the wrong option for {ip} - should be
ip=self.entry.name
>
>> return
>>
>> - def process_sver(self, data, *args, **kwargs):
>> + def process_sver(self, data):
>> """
>> Software version of projector
>> """
>> @@ -1181,7 +1187,7 @@
>> try:
>> self.readyRead.
>> except TypeError:
>> - pass
>> + log.debug('({ip}) disconnect_
>
> You're just disconnecting a slot here right? Do we need to log that?
Since this is in the projector instance, I would like to know if
there's a type issue - if so, then I would like to see it in the log.
>
>> log.debug('({ip}) disconnect_
>> 'Current status {data}'
>> if abort:
>
>
> --
> https:/
> You are the owner of lp:~alisonken1/openlp/pjlink2-r.
--
- Ken
Registered Linux user 296561
Slackin' since 1993
Slackware Linux (http://
OpenLP - Church Projection Software
Empower Your Church http://
On Sat, Apr 28, 2018 at 12:15 AM, Phill <email address hidden> wrote:
> Review: Needs Fixing
>
> Ran out of time to complete a review, but a few in lines to start.
>
> Diff comments:
>
>>
>> === modified file 'openlp/
>> --- openlp/
>> +++ openlp/
>> @@ -513,6 +519,18 @@
>> projector.
>> except (AttributeError, TypeError):
>> pass
>> + # Disconnect signals from projector being deleted
>> + try:
>> + self.pjlink_
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Phill (phill-ridout) wrote : Posted in a previous version of this proposal | # |
See inlines please.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Phill (phill-ridout) : Posted in a previous version of this proposal | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Phill (phill-ridout) wrote : | # |
Sorry, reviewed a previous version.
- 2819. By Ken Roberts
-
PJLink2 update R
- 2820. By Ken Roberts
-
Fix settings calls
Unmerged revisions
Preview Diff
1 | === modified file 'openlp/core/common/settings.py' |
2 | --- openlp/core/common/settings.py 2018-02-02 21:33:41 +0000 |
3 | +++ openlp/core/common/settings.py 2018-05-03 14:59:14 +0000 |
4 | @@ -199,6 +199,7 @@ |
5 | 'projector/db database': '', |
6 | 'projector/enable': True, |
7 | 'projector/connect on start': False, |
8 | + 'projector/connect when LKUP received': True, # PJLink v2: Projector sends LKUP command after it powers up |
9 | 'projector/last directory import': None, |
10 | 'projector/last directory export': None, |
11 | 'projector/poll time': 20, # PJLink timeout is 30 seconds |
12 | |
13 | === modified file 'openlp/core/projectors/manager.py' |
14 | --- openlp/core/projectors/manager.py 2018-04-20 06:04:43 +0000 |
15 | +++ openlp/core/projectors/manager.py 2018-05-03 14:59:14 +0000 |
16 | @@ -37,7 +37,7 @@ |
17 | from openlp.core.projectors import DialogSourceStyle |
18 | from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, \ |
19 | E_UNKNOWN_SOCKET_ERROR, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, \ |
20 | - S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG, QSOCKET_STATE |
21 | + S_STANDBY, S_WARMUP, PJLINK_PORT, STATUS_CODE, STATUS_MSG, QSOCKET_STATE |
22 | |
23 | from openlp.core.projectors.db import ProjectorDB |
24 | from openlp.core.projectors.editform import ProjectorEditForm |
25 | @@ -294,6 +294,9 @@ |
26 | self.projectordb = projectordb |
27 | self.projector_list = [] |
28 | self.source_select_form = None |
29 | + # Dictionary of PJLinkUDP objects to listen for UDP broadcasts from PJLink 2+ projectors. |
30 | + # Key is port number that projectors use |
31 | + self.pjlink_udp = {} |
32 | |
33 | def bootstrap_initialise(self): |
34 | """ |
35 | @@ -307,12 +310,15 @@ |
36 | else: |
37 | log.debug('Using existing ProjectorDB() instance') |
38 | self.get_settings() |
39 | - self.pjlink_udp = PJLinkUDP(self.projector_list) |
40 | |
41 | def bootstrap_post_set_up(self): |
42 | """ |
43 | Post-initialize setups. |
44 | """ |
45 | + # Default PJLink port UDP socket |
46 | + log.debug('Creating PJLinkUDP listener for default port {port}'.format(port=PJLINK_PORT)) |
47 | + self.pjlink_udp = {PJLINK_PORT: PJLinkUDP(port=PJLINK_PORT)} |
48 | + self.pjlink_udp[PJLINK_PORT].bind(PJLINK_PORT) |
49 | # Set 1.5 second delay before loading all projectors |
50 | if self.autostart: |
51 | log.debug('Delaying 1.5 seconds before loading all projectors') |
52 | @@ -513,6 +519,14 @@ |
53 | projector.socket_timer.timeout.disconnect(projector.link.socket_abort) |
54 | except (AttributeError, TypeError): |
55 | pass |
56 | + # Disconnect signals from projector being deleted |
57 | + if self.pjlink_udp[projector.port]: |
58 | + try: |
59 | + self.pjlink_udp[projector.port].data_received.disconnect(projector.get_buffer) |
60 | + except (AttributeError, TypeError): |
61 | + pass |
62 | + |
63 | + # Rebuild projector list |
64 | new_list = [] |
65 | for item in self.projector_list: |
66 | if item.link.db_item.id == projector.link.db_item.id: |
67 | @@ -726,6 +740,15 @@ |
68 | item.link.projectorAuthentication.connect(self.authentication_error) |
69 | item.link.projectorNoAuthentication.connect(self.no_authentication_error) |
70 | item.link.projectorUpdateIcons.connect(self.update_icons) |
71 | + # Connect UDP signal to projector instances with same port |
72 | + if item.link.port not in self.pjlink_udp: |
73 | + log.debug('Adding new PJLinkUDP listener fo port {port}'.format(port=item.link.port)) |
74 | + self.pjlink_udp[item.link.port] = PJLinkUDP(port=item.link.port) |
75 | + self.pjlink_udp[item.link.port].bind(item.link.port) |
76 | + log.debug('Connecting PJLinkUDP port {port} signal to "{item}"'.format(port=item.link.port, |
77 | + item=item.link.name)) |
78 | + self.pjlink_udp[item.link.port].data_received.connect(item.link.get_buffer) |
79 | + |
80 | self.projector_list.append(item) |
81 | if start: |
82 | item.link.connect_to_host() |
83 | |
84 | === modified file 'openlp/core/projectors/pjlink.py' |
85 | --- openlp/core/projectors/pjlink.py 2018-04-20 06:04:43 +0000 |
86 | +++ openlp/core/projectors/pjlink.py 2018-05-03 14:59:14 +0000 |
87 | @@ -54,6 +54,7 @@ |
88 | |
89 | from openlp.core.common import qmd5_hash |
90 | from openlp.core.common.i18n import translate |
91 | +from openlp.core.common.settings import Settings |
92 | from openlp.core.projectors.constants import CONNECTION_ERRORS, PJLINK_CLASS, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \ |
93 | PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PREFIX, PJLINK_PORT, PJLINK_POWR_STATUS, \ |
94 | PJLINK_SUFFIX, PJLINK_VALID_CMD, PROJECTOR_STATE, STATUS_CODE, STATUS_MSG, QSOCKET_STATE, \ |
95 | @@ -78,25 +79,27 @@ |
96 | """ |
97 | Socket service for PJLink UDP socket. |
98 | """ |
99 | - def __init__(self, projector_list, port=PJLINK_PORT): |
100 | + |
101 | + data_received = QtCore.pyqtSignal(QtNetwork.QHostAddress, int, str, name='udp_data') # host, port, data |
102 | + |
103 | + def __init__(self, port=PJLINK_PORT): |
104 | """ |
105 | Socket services for PJLink UDP packets. |
106 | |
107 | Since all UDP packets from any projector will come into the same |
108 | port, process UDP packets here then route to the appropriate |
109 | projector instance as needed. |
110 | + |
111 | + :param port: UDP port to listen on |
112 | """ |
113 | - # Keep track of currently defined projectors so we can route |
114 | - # inbound packets to the correct instance |
115 | super().__init__() |
116 | - self.projector_list = projector_list |
117 | self.port = port |
118 | # Local defines |
119 | self.search_active = False |
120 | self.search_time = 30000 # 30 seconds for allowed time |
121 | self.search_timer = QtCore.QTimer() |
122 | self.readyRead.connect(self.get_datagram) |
123 | - log.debug('(UDP) PJLinkUDP() Initialized') |
124 | + log.debug('(UDP) PJLinkUDP() Initialized for port {port}'.format(port=self.port)) |
125 | |
126 | @QtCore.pyqtSlot() |
127 | def get_datagram(self): |
128 | @@ -105,25 +108,23 @@ |
129 | """ |
130 | log.debug('(UDP) get_datagram() - Receiving data') |
131 | read_size = self.pendingDatagramSize() |
132 | - if read_size < 0: |
133 | + if -1 == read_size: |
134 | log.warning('(UDP) No data (-1)') |
135 | return |
136 | - if read_size < 1: |
137 | + elif 0 == read_size: |
138 | log.warning('(UDP) get_datagram() called when pending data size is 0') |
139 | return |
140 | - data, peer_address, peer_port = self.readDatagram(self.pendingDatagramSize()) |
141 | + elif read_size > PJLINK_MAX_PACKET: |
142 | + log.warning('(UDP) UDP Packet too large ({size} bytes)- ignoring'.format(size=read_size)) |
143 | + return |
144 | + data_in, peer_host, peer_port = self.readDatagram(read_size) |
145 | + data = data_in.decode('utf-8') if isinstance(data_in, bytes) else data_in |
146 | log.debug('(UDP) {size} bytes received from {adx} on port {port}'.format(size=len(data), |
147 | - adx=peer_address, |
148 | - port=peer_port)) |
149 | + adx=peer_host.toString(), |
150 | + port=self.port)) |
151 | log.debug('(UDP) packet "{data}"'.format(data=data)) |
152 | - # Send to appropriate instance to process packet |
153 | - log.debug('(UDP) Checking projector list for ip {host} to process'.format(host=peer_address)) |
154 | - for projector in self.projector_list: |
155 | - if peer_address == projector.ip: |
156 | - # Dispatch packet to appropriate remote instance |
157 | - log.debug('(UDP) Dispatching packet to {host}'.format(host=projector.entry.name)) |
158 | - return projector.get_data(buff=data, ip=peer_address, host=peer_address, port=peer_port) |
159 | - log.warning('(UDP) Could not find projector with ip {ip} to process packet'.format(ip=peer_address)) |
160 | + log.debug('(UDP) Sending data_received signal to projectors') |
161 | + self.data_received.emit(peer_host, self.localPort(), data) |
162 | return |
163 | |
164 | def search_start(self): |
165 | @@ -131,7 +132,6 @@ |
166 | Start search for projectors on local network |
167 | """ |
168 | self.search_active = True |
169 | - self.ackn_list = {} |
170 | # TODO: Send SRCH packet here |
171 | self.search_timer.singleShot(self.search_time, self.search_stop) |
172 | |
173 | @@ -240,7 +240,7 @@ |
174 | for cmd in self.pjlink_functions: |
175 | self.pjlink_functions[cmd]["version"] = PJLINK_VALID_CMD[cmd]['default'] |
176 | |
177 | - def process_command(self, cmd, data, *args, **kwargs): |
178 | + def process_command(self, cmd, data): |
179 | """ |
180 | Verifies any return error code. Calls the appropriate command handler. |
181 | |
182 | @@ -272,25 +272,18 @@ |
183 | return self.change_status(status=E_AUTHENTICATION) |
184 | # Command checks already passed |
185 | log.debug('({ip}) Calling function for {cmd}'.format(ip=self.entry.name, cmd=cmd)) |
186 | - self.pjlink_functions[cmd]["method"](data=data, *args, **kwargs) |
187 | + self.pjlink_functions[cmd]["method"](data=data) |
188 | |
189 | - def process_ackn(self, data, host, port): |
190 | + def process_ackn(self, data): |
191 | """ |
192 | Process the ACKN command. |
193 | |
194 | :param data: Data in packet |
195 | - :param host: IP address of sending host |
196 | - :param port: Port received on |
197 | """ |
198 | - log.debug('({ip}) Processing ACKN packet'.format(ip=self.entry.name)) |
199 | - if host not in self.ackn_list: |
200 | - log.debug('({ip}) Adding {host} to ACKN list'.format(ip=self.entry.name, host=host)) |
201 | - self.ackn_list[host] = {'data': data, |
202 | - 'port': port} |
203 | - else: |
204 | - log.warning('({ip}) Host {host} already replied - ignoring'.format(ip=self.entry.name, host=host)) |
205 | + # TODO: Have to rethink this one |
206 | + pass |
207 | |
208 | - def process_avmt(self, data, *args, **kwargs): |
209 | + def process_avmt(self, data): |
210 | """ |
211 | Process shutter and speaker status. See PJLink specification for format. |
212 | Update self.mute (audio) and self.shutter (video shutter). |
213 | @@ -319,7 +312,7 @@ |
214 | self.projectorUpdateIcons.emit() |
215 | return |
216 | |
217 | - def process_clss(self, data, *args, **kwargs): |
218 | + def process_clss(self, data): |
219 | """ |
220 | PJLink class that this projector supports. See PJLink specification for format. |
221 | Updates self.class. |
222 | @@ -365,7 +358,7 @@ |
223 | |
224 | return |
225 | |
226 | - def process_erst(self, data, *args, **kwargs): |
227 | + def process_erst(self, data): |
228 | """ |
229 | Error status. See PJLink Specifications for format. |
230 | Updates self.projector_errors |
231 | @@ -417,7 +410,7 @@ |
232 | PJLINK_ERST_STATUS[other] |
233 | return |
234 | |
235 | - def process_inf1(self, data, *args, **kwargs): |
236 | + def process_inf1(self, data): |
237 | """ |
238 | Manufacturer name set in projector. |
239 | Updates self.manufacturer |
240 | @@ -429,7 +422,7 @@ |
241 | data=self.manufacturer)) |
242 | return |
243 | |
244 | - def process_inf2(self, data, *args, **kwargs): |
245 | + def process_inf2(self, data): |
246 | """ |
247 | Projector Model set in projector. |
248 | Updates self.model. |
249 | @@ -440,7 +433,7 @@ |
250 | log.debug('({ip}) Setting projector model to "{data}"'.format(ip=self.entry.name, data=self.model)) |
251 | return |
252 | |
253 | - def process_info(self, data, *args, **kwargs): |
254 | + def process_info(self, data): |
255 | """ |
256 | Any extra info set in projector. |
257 | Updates self.other_info. |
258 | @@ -451,7 +444,7 @@ |
259 | log.debug('({ip}) Setting projector other_info to "{data}"'.format(ip=self.entry.name, data=self.other_info)) |
260 | return |
261 | |
262 | - def process_inpt(self, data, *args, **kwargs): |
263 | + def process_inpt(self, data): |
264 | """ |
265 | Current source input selected. See PJLink specification for format. |
266 | Update self.source |
267 | @@ -473,7 +466,7 @@ |
268 | log.debug('({ip}) Setting data source to "{data}"'.format(ip=self.entry.name, data=self.source)) |
269 | return |
270 | |
271 | - def process_inst(self, data, *args, **kwargs): |
272 | + def process_inst(self, data): |
273 | """ |
274 | Available source inputs. See PJLink specification for format. |
275 | Updates self.source_available |
276 | @@ -490,7 +483,7 @@ |
277 | data=self.source_available)) |
278 | return |
279 | |
280 | - def process_lamp(self, data, *args, **kwargs): |
281 | + def process_lamp(self, data): |
282 | """ |
283 | Lamp(s) status. See PJLink Specifications for format. |
284 | Data may have more than 1 lamp to process. |
285 | @@ -516,18 +509,22 @@ |
286 | self.lamp = lamps |
287 | return |
288 | |
289 | - def process_lkup(self, data, host, port): |
290 | + def process_lkup(self, data): |
291 | """ |
292 | Process reply indicating remote is available for connection |
293 | |
294 | :param data: Data packet from remote |
295 | - :param host: Remote IP address |
296 | - :param port: Local port packet received on |
297 | """ |
298 | - # TODO: Check if autoconnect is enabled and connect? |
299 | - pass |
300 | + log.debug('({ip}) Processing LKUP command'.format(ip=self.entry.name)) |
301 | + settings = Settings() |
302 | + settings.beginGroup(self.settings_section) |
303 | + autostart = settings.value('connect when LKUP received') |
304 | + settings.endGroup() |
305 | + del settings |
306 | + if autostart: |
307 | + self.connect_to_host() |
308 | |
309 | - def process_name(self, data, *args, **kwargs): |
310 | + def process_name(self, data): |
311 | """ |
312 | Projector name set in projector. |
313 | Updates self.pjlink_name |
314 | @@ -538,7 +535,7 @@ |
315 | log.debug('({ip}) Setting projector PJLink name to "{data}"'.format(ip=self.entry.name, data=self.pjlink_name)) |
316 | return |
317 | |
318 | - def process_pjlink(self, data, *args, **kwargs): |
319 | + def process_pjlink(self, data): |
320 | """ |
321 | Process initial socket connection to terminal. |
322 | |
323 | @@ -579,7 +576,7 @@ |
324 | # Since this is an initial connection, make it a priority just in case |
325 | return self.send_command(cmd="CLSS", salt=data_hash, priority=True) |
326 | |
327 | - def process_powr(self, data, *args, **kwargs): |
328 | + def process_powr(self, data): |
329 | """ |
330 | Power status. See PJLink specification for format. |
331 | Update self.power with status. Update icons if change from previous setting. |
332 | @@ -602,7 +599,7 @@ |
333 | log.warning('({ip}) Unknown power response: "{data}"'.format(ip=self.entry.name, data=data)) |
334 | return |
335 | |
336 | - def process_rfil(self, data, *args, **kwargs): |
337 | + def process_rfil(self, data): |
338 | """ |
339 | Process replacement filter type |
340 | """ |
341 | @@ -613,7 +610,7 @@ |
342 | log.warning('({ip}) Saved model: "{old}"'.format(ip=self.entry.name, old=self.model_filter)) |
343 | log.warning('({ip}) New model: "{new}"'.format(ip=self.entry.name, new=data)) |
344 | |
345 | - def process_rlmp(self, data, *args, **kwargs): |
346 | + def process_rlmp(self, data): |
347 | """ |
348 | Process replacement lamp type |
349 | """ |
350 | @@ -624,7 +621,7 @@ |
351 | log.warning('({ip}) Saved lamp: "{old}"'.format(ip=self.entry.name, old=self.model_lamp)) |
352 | log.warning('({ip}) New lamp: "{new}"'.format(ip=self.entry.name, new=data)) |
353 | |
354 | - def process_snum(self, data, *args, **kwargs): |
355 | + def process_snum(self, data): |
356 | """ |
357 | Serial number of projector. |
358 | |
359 | @@ -644,20 +641,18 @@ |
360 | log.warning('({ip}) NOT saving serial number'.format(ip=self.entry.name)) |
361 | self.serial_no_received = data |
362 | |
363 | - def process_srch(self, data, host, port): |
364 | + def process_srch(self, data): |
365 | """ |
366 | Process the SRCH command. |
367 | |
368 | SRCH is processed by terminals so we ignore any packet. |
369 | |
370 | :param data: Data in packet |
371 | - :param host: IP address of sending host |
372 | - :param port: Port received on |
373 | """ |
374 | - log.warning('(UDP) SRCH packet received from {host} - ignoring'.format(host=host)) |
375 | + log.warning("({ip}) SRCH packet detected - ignoring".format(ip=self.entry.ip)) |
376 | return |
377 | |
378 | - def process_sver(self, data, *args, **kwargs): |
379 | + def process_sver(self, data): |
380 | """ |
381 | Software version of projector |
382 | """ |
383 | @@ -705,14 +700,16 @@ |
384 | args=args, |
385 | kwargs=kwargs)) |
386 | super().__init__() |
387 | + self.settings_section = 'projector' |
388 | self.entry = projector |
389 | self.ip = self.entry.ip |
390 | + self.qhost = QtNetwork.QHostAddress(self.ip) |
391 | self.location = self.entry.location |
392 | self.mac_adx = self.entry.mac_adx |
393 | self.name = self.entry.name |
394 | self.notes = self.entry.notes |
395 | self.pin = self.entry.pin |
396 | - self.port = self.entry.port |
397 | + self.port = int(self.entry.port) |
398 | self.pjlink_class = PJLINK_CLASS if self.entry.pjlink_class is None else self.entry.pjlink_class |
399 | self.ackn_list = {} # Replies from online projectors (Class 2 option) |
400 | self.db_update = False # Use to check if db needs to be updated prior to exiting |
401 | @@ -928,19 +925,21 @@ |
402 | count=trash_count)) |
403 | return |
404 | |
405 | - @QtCore.pyqtSlot(str, str) |
406 | - def get_buffer(self, data, ip): |
407 | + @QtCore.pyqtSlot(QtNetwork.QHostAddress, int, str, name='udp_data') # host, port, data |
408 | + def get_buffer(self, host, port, data): |
409 | """ |
410 | Get data from somewhere other than TCP socket |
411 | |
412 | + :param host: QHostAddress of sender |
413 | + :param port: Destination port |
414 | :param data: Data to process. buffer must be formatted as a proper PJLink packet. |
415 | - :param ip: Destination IP for buffer. |
416 | """ |
417 | - log.debug('({ip}) get_buffer(data="{buff}" ip="{ip_in}"'.format(ip=self.entry.name, buff=data, ip_in=ip)) |
418 | - if ip is None: |
419 | - log.debug("({ip}) get_buffer() Don't know who data is for - exiting".format(ip=self.entry.name)) |
420 | - return |
421 | - return self.get_data(buff=data, ip=ip) |
422 | + if (port == int(self.port)) and (host.isEqual(self.qhost)): |
423 | + log.debug('({ip}) Received data from {host}'.format(ip=self.entry.name, host=host.toString())) |
424 | + log.debug('({ip}) get_buffer(data="{buff}")'.format(ip=self.entry.name, buff=data)) |
425 | + return self.get_data(buff=data) |
426 | + else: |
427 | + log.debug('({ip}) Ignoring data for {host} - not me'.format(ip=self.entry.name, host=host.toString())) |
428 | |
429 | @QtCore.pyqtSlot() |
430 | def get_socket(self): |
431 | @@ -960,20 +959,16 @@ |
432 | log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.entry.name)) |
433 | return self.receive_data_signal() |
434 | self.socket_timer.stop() |
435 | - return self.get_data(buff=read, ip=self.ip) |
436 | + return self.get_data(buff=read) |
437 | |
438 | - def get_data(self, buff, ip=None, *args, **kwargs): |
439 | + def get_data(self, buff, *args, **kwargs): |
440 | """ |
441 | Process received data |
442 | |
443 | :param buff: Data to process. |
444 | - :param ip: (optional) Destination IP. |
445 | """ |
446 | - # Since "self" is not available to options and the "ip" keyword is a "maybe I'll use in the future", |
447 | - # set to default here |
448 | - if ip is None: |
449 | - ip = self.ip |
450 | - log.debug('({ip}) get_data(ip="{ip_in}" buffer="{buff}"'.format(ip=self.entry.name, ip_in=ip, buff=buff)) |
451 | + log.debug('({ip}) get_data(buffer="{buff}"'.format(ip=self.entry.name, buff=buff)) |
452 | + ignore_class = 'ignore_class' in kwargs |
453 | # NOTE: Class2 has changed to some values being UTF-8 |
454 | if isinstance(buff, bytes): |
455 | data_in = decode(buff, 'utf-8') |
456 | @@ -990,7 +985,9 @@ |
457 | elif not data.startswith(PJLINK_PREFIX): |
458 | self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing') |
459 | return self.receive_data_signal() |
460 | - elif data[6] != '=': |
461 | + elif data[6] != '=' and data[8] != '=': |
462 | + # data[6] = standard command packet |
463 | + # data[8] = initial PJLink connection (after mangling) |
464 | self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="') |
465 | return self.receive_data_signal() |
466 | log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.entry.name, data=data)) |
467 | @@ -1020,16 +1017,16 @@ |
468 | return self.receive_data_signal() |
469 | ''' |
470 | if cmd not in PJLINK_VALID_CMD: |
471 | - self._trash_buffer('get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.entry.name, |
472 | - data=cmd)) |
473 | + self._trash_buffer('get_data(): Invalid packet - unknown command "{data}"'.format(data=cmd)) |
474 | return self.receive_data_signal() |
475 | elif version not in PJLINK_VALID_CMD[cmd]['version']: |
476 | self._trash_buffer(msg='get_data() Command reply version does not match a valid command version') |
477 | return self.receive_data_signal() |
478 | elif int(self.pjlink_class) < int(version): |
479 | - log.warning('({ip}) get_data(): Projector returned class reply higher ' |
480 | - 'than projector stated class'.format(ip=self.entry.name)) |
481 | - self.process_command(cmd, data, *args, **kwargs) |
482 | + if not ignore_class: |
483 | + log.warning('({ip}) get_data(): Projector returned class reply higher ' |
484 | + 'than projector stated class'.format(ip=self.entry.name)) |
485 | + self.process_command(cmd, data) |
486 | return self.receive_data_signal() |
487 | |
488 | @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError) |
489 | @@ -1107,11 +1104,18 @@ |
490 | """ |
491 | Socket interface to send data. If data=None, then check queue. |
492 | |
493 | - :param data: Immediate data to send |
494 | + :param data: Immediate data to send (Optional) |
495 | :param utf8: Send as UTF-8 string otherwise send as ASCII string |
496 | """ |
497 | - # Funny looking data check, but it's a quick check for data=None |
498 | - log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.entry.name, data=data.strip() if data else data)) |
499 | + if not data and not self.priority_queue and not self.send_queue: |
500 | + log.debug('({ip}) _send_command(): Nothing to send - returning'.format(ip=self.entry.name)) |
501 | + return |
502 | + log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.entry.name, |
503 | + data=data.strip() if data else data)) |
504 | + log.debug('({ip}) _send_command(): priority_queue: {queue}'.format(ip=self.entry.name, |
505 | + queue=self.priority_queue)) |
506 | + log.debug('({ip}) _send_command(): send_queue: {queue}'.format(ip=self.entry.name, |
507 | + queue=self.send_queue)) |
508 | conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]] |
509 | log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.entry.name, |
510 | data=conn_state)) |
511 | @@ -1149,9 +1153,9 @@ |
512 | self.waitForBytesWritten(2000) # 2 seconds should be enough |
513 | if sent == -1: |
514 | # Network error? |
515 | - log.warning('({ip}) _send_command(): -1 received - disconnecting from host'.format(ip=self.entry.name)) |
516 | self.change_status(E_NETWORK, |
517 | translate('OpenLP.PJLink', 'Error while sending data to projector')) |
518 | + log.warning('({ip}) _send_command(): -1 received - disconnecting from host'.format(ip=self.entry.name)) |
519 | self.disconnect_from_host() |
520 | |
521 | def connect_to_host(self): |
522 | @@ -1164,7 +1168,7 @@ |
523 | return |
524 | self.error_status = S_OK |
525 | self.change_status(S_CONNECTING) |
526 | - self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port)) |
527 | + self.connectToHost(self.ip, self.port) |
528 | |
529 | @QtCore.pyqtSlot() |
530 | def disconnect_from_host(self, abort=False): |
531 | @@ -1177,13 +1181,15 @@ |
532 | self.abort() |
533 | else: |
534 | log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.entry.name)) |
535 | - self.disconnectFromHost() |
536 | try: |
537 | self.readyRead.disconnect(self.get_socket) |
538 | except TypeError: |
539 | - pass |
540 | - log.debug('({ip}) disconnect_from_host() ' |
541 | + # Since we already know what's happening, just log it for reference. |
542 | + log.debug('({ip}) disconnect_from_host(): Issue detected with ' |
543 | + 'readyRead.disconnect'.format(ip=self.entry.name)) |
544 | + log.debug('({ip}) disconnect_from_host(): ' |
545 | 'Current status {data}'.format(ip=self.entry.name, data=self._get_status(self.status_connect)[0])) |
546 | + self.disconnectFromHost() |
547 | if abort: |
548 | self.change_status(E_NOT_CONNECTED) |
549 | else: |
550 | |
551 | === modified file 'openlp/core/projectors/tab.py' |
552 | --- openlp/core/projectors/tab.py 2017-12-29 09:15:48 +0000 |
553 | +++ openlp/core/projectors/tab.py 2018-05-03 14:59:14 +0000 |
554 | @@ -89,6 +89,10 @@ |
555 | self.connect_box_layout.addRow(self.dialog_type_label, self.dialog_type_combo_box) |
556 | self.left_layout.addStretch() |
557 | self.dialog_type_combo_box.activated.connect(self.on_dialog_type_combo_box_changed) |
558 | + # Connect on LKUP packet received (PJLink v2+ only) |
559 | + self.connect_on_linkup = QtWidgets.QCheckBox(self.connect_box) |
560 | + self.connect_on_linkup.setObjectName('connect_on_linkup') |
561 | + self.connect_box_layout.addRow(self.connect_on_linkup) |
562 | |
563 | def retranslateUi(self): |
564 | """ |
565 | @@ -109,6 +113,8 @@ |
566 | translate('OpenLP.ProjectorTab', 'Tabbed dialog box')) |
567 | self.dialog_type_combo_box.setItemText(DialogSourceStyle.Single, |
568 | translate('OpenLP.ProjectorTab', 'Single dialog box')) |
569 | + self.connect_on_linkup.setText( |
570 | + translate('OpenLP.ProjectorTab', 'Connect to projector when LINKUP received (v2 only)')) |
571 | |
572 | def load(self): |
573 | """ |
574 | @@ -120,6 +126,7 @@ |
575 | self.socket_timeout_spin_box.setValue(settings.value('socket timeout')) |
576 | self.socket_poll_spin_box.setValue(settings.value('poll time')) |
577 | self.dialog_type_combo_box.setCurrentIndex(settings.value('source dialog type')) |
578 | + self.connect_on_linkup.setChecked(settings.value('connect when LKUP received')) |
579 | settings.endGroup() |
580 | |
581 | def save(self): |
582 | @@ -132,6 +139,7 @@ |
583 | settings.setValue('socket timeout', self.socket_timeout_spin_box.value()) |
584 | settings.setValue('poll time', self.socket_poll_spin_box.value()) |
585 | settings.setValue('source dialog type', self.dialog_type_combo_box.currentIndex()) |
586 | + settings.setValue('connect when LKUP received', self.connect_on_linkup.isChecked()) |
587 | settings.endGroup() |
588 | |
589 | def on_dialog_type_combo_box_changed(self): |
590 | |
591 | === renamed file 'tests/openlp_core/projectors/test_projector_pjlink_base.py' => 'tests/openlp_core/projectors/test_projector_pjlink_base_01.py' |
592 | --- tests/openlp_core/projectors/test_projector_pjlink_base.py 2018-01-13 05:41:42 +0000 |
593 | +++ tests/openlp_core/projectors/test_projector_pjlink_base_01.py 2018-05-03 14:59:14 +0000 |
594 | @@ -27,23 +27,13 @@ |
595 | |
596 | import openlp.core.projectors.pjlink |
597 | from openlp.core.projectors.constants import \ |
598 | - E_NOT_CONNECTED, \ |
599 | - E_PARAMETER, \ |
600 | - E_UNKNOWN_SOCKET_ERROR, \ |
601 | - STATUS_CODE, \ |
602 | - STATUS_MSG, \ |
603 | - S_CONNECTED, \ |
604 | - S_CONNECTING, \ |
605 | - S_NOT_CONNECTED, \ |
606 | - S_OK, \ |
607 | - S_ON, \ |
608 | + E_NOT_CONNECTED, E_PARAMETER, E_UNKNOWN_SOCKET_ERROR, STATUS_CODE, STATUS_MSG, \ |
609 | + S_CONNECTED, S_CONNECTING, S_NOT_CONNECTED, S_OK, S_ON, \ |
610 | QSOCKET_STATE |
611 | from openlp.core.projectors.db import Projector |
612 | from openlp.core.projectors.pjlink import PJLink |
613 | from tests.resources.projector.data import TEST1_DATA |
614 | |
615 | -pjlink_test = PJLink(Projector(**TEST1_DATA), no_poll=True) |
616 | - |
617 | |
618 | class TestPJLinkBase(TestCase): |
619 | """ |
620 | |
621 | === added file 'tests/openlp_core/projectors/test_projector_pjlink_base_02.py' |
622 | --- tests/openlp_core/projectors/test_projector_pjlink_base_02.py 1970-01-01 00:00:00 +0000 |
623 | +++ tests/openlp_core/projectors/test_projector_pjlink_base_02.py 2018-05-03 14:59:14 +0000 |
624 | @@ -0,0 +1,101 @@ |
625 | +# -*- coding: utf-8 -*- |
626 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
627 | + |
628 | +############################################################################### |
629 | +# OpenLP - Open Source Lyrics Projection # |
630 | +# --------------------------------------------------------------------------- # |
631 | +# Copyright (c) 2008-2015 OpenLP Developers # |
632 | +# --------------------------------------------------------------------------- # |
633 | +# This program is free software; you can redistribute it and/or modify it # |
634 | +# under the terms of the GNU General Public License as published by the Free # |
635 | +# Software Foundation; version 2 of the License. # |
636 | +# # |
637 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
638 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
639 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
640 | +# more details. # |
641 | +# # |
642 | +# You should have received a copy of the GNU General Public License along # |
643 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
644 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
645 | +############################################################################### |
646 | +""" |
647 | +Package to test the openlp.core.projectors.pjlink base package. |
648 | +""" |
649 | +from unittest import TestCase |
650 | +from unittest.mock import call, patch |
651 | + |
652 | +import openlp.core.projectors.pjlink |
653 | + |
654 | +from openlp.core.projectors.constants import S_NOT_CONNECTED |
655 | +from openlp.core.projectors.db import Projector |
656 | +from openlp.core.projectors.pjlink import PJLink |
657 | +from tests.resources.projector.data import TEST1_DATA |
658 | + |
659 | + |
660 | +class TestPJLinkBase(TestCase): |
661 | + """ |
662 | + Tests for the PJLink module |
663 | + """ |
664 | + @patch.object(openlp.core.projectors.pjlink.PJLink, 'state') |
665 | + @patch.object(openlp.core.projectors.pjlink.PJLink, 'reset_information') |
666 | + @patch.object(openlp.core.projectors.pjlink.PJLink, '_send_command') |
667 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
668 | + def test_send_command_no_data(self, mock_log, mock_send_command, mock_reset, mock_state): |
669 | + """ |
670 | + Test _send_command with no data to send |
671 | + """ |
672 | + # GIVEN: Test object |
673 | + log_warning_calls = [call('({ip}) send_command(): Not connected - returning'.format(ip=TEST1_DATA['name']))] |
674 | + |
675 | + log_debug_calls = [call('PJlink(projector="< Projector(id="None", ip="111.111.111.111", port="1111", ' |
676 | + 'mac_adx="11:11:11:11:11:11", pin="1111", name="___TEST_ONE___", ' |
677 | + 'location="location one", notes="notes one", pjlink_name="None", ' |
678 | + 'pjlink_class="None", manufacturer="None", model="None", ' |
679 | + 'serial_no="Serial Number 1", other="None", sources="None", source_list="[]", ' |
680 | + 'model_filter="Filter type 1", model_lamp="Lamp type 1", ' |
681 | + 'sw_version="Version 1") >", args="()" kwargs="{\'no_poll\': True}")'), |
682 | + call('PJlinkCommands(args=() kwargs={})')] |
683 | + mock_state.return_value = S_NOT_CONNECTED |
684 | + pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True) |
685 | + pjlink.send_queue = [] |
686 | + pjlink.priority_queue = [] |
687 | + |
688 | + # WHEN: _send_command called with no data and queue's empty |
689 | + pjlink.send_command(cmd='DONTCARE') |
690 | + |
691 | + # THEN: |
692 | + mock_log.debug.assert_has_calls(log_debug_calls) |
693 | + mock_log.warning.assert_has_calls(log_warning_calls) |
694 | + assert mock_reset.called is True |
695 | + assert mock_reset.called is True |
696 | + |
697 | + @patch.object(openlp.core.projectors.pjlink, 'log') |
698 | + def test_local_send_command_no_data(self, mock_log): |
699 | + """ |
700 | + Test _send_command with no data to send |
701 | + """ |
702 | + # GIVEN: Test object |
703 | + log_debug_calls = [call('PJlink(projector="< Projector(id="None", ip="111.111.111.111", port="1111", ' |
704 | + 'mac_adx="11:11:11:11:11:11", pin="1111", name="___TEST_ONE___", ' |
705 | + 'location="location one", notes="notes one", pjlink_name="None", ' |
706 | + 'pjlink_class="None", manufacturer="None", model="None", ' |
707 | + 'serial_no="Serial Number 1", other="None", sources="None", source_list="[]", ' |
708 | + 'model_filter="Filter type 1", model_lamp="Lamp type 1", ' |
709 | + 'sw_version="Version 1") >", args="()" kwargs="{\'no_poll\': True}")'), |
710 | + call('PJlinkCommands(args=() kwargs={})'), |
711 | + call('(___TEST_ONE___) reset_information() connect status is S_NOT_CONNECTED'), |
712 | + call('(___TEST_ONE___) _send_command(): Nothing to send - returning')] |
713 | + |
714 | + pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True) |
715 | + pjlink.send_queue = [] |
716 | + pjlink.priority_queue = [] |
717 | + |
718 | + # WHEN: _send_command called with no data and queue's emtpy |
719 | + # Patch here since pjlink does not have socket_timer until after instantiation |
720 | + with patch.object(pjlink, 'socket_timer') as mock_timer: |
721 | + pjlink._send_command(data=None, utf8=False) |
722 | + |
723 | + # THEN: |
724 | + mock_log.debug.assert_has_calls(log_debug_calls) |
725 | + assert mock_timer.called is False |
726 | |
727 | === modified file 'tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py' |
728 | --- tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2018-04-20 06:04:43 +0000 |
729 | +++ tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2018-05-03 14:59:14 +0000 |
730 | @@ -49,13 +49,23 @@ |
731 | pjlink.pjlink_functions = MagicMock() |
732 | log_warning_text = [call('({ip}) get_data(): Invalid packet - ' |
733 | 'unknown command "UNKN"'.format(ip=pjlink.name))] |
734 | - log_debug_text = [call('(___TEST_ONE___) get_data(ip="111.111.111.111" buffer="%1UNKN=Huh?"'), |
735 | + log_debug_text = [call('PJlink(projector="< Projector(id="None", ip="111.111.111.111", port="1111", ' |
736 | + 'mac_adx="11:11:11:11:11:11", pin="1111", name="___TEST_ONE___", ' |
737 | + 'location="location one", notes="notes one", pjlink_name="None", ' |
738 | + 'pjlink_class="None", manufacturer="None", model="None", serial_no="Serial Number 1", ' |
739 | + 'other="None", sources="None", source_list="[]", model_filter="Filter type 1", ' |
740 | + 'model_lamp="Lamp type 1", sw_version="Version 1") >", ' |
741 | + 'args="()" kwargs="{\'no_poll\': True}")'), |
742 | + call('PJlinkCommands(args=() kwargs={})'), |
743 | + call('(___TEST_ONE___) reset_information() connect status is S_NOT_CONNECTED'), |
744 | + call('(___TEST_ONE___) get_data(buffer="%1UNKN=Huh?"'), |
745 | call('(___TEST_ONE___) get_data(): Checking new data "%1UNKN=Huh?"'), |
746 | call('(___TEST_ONE___) get_data() header="%1UNKN" data="Huh?"'), |
747 | call('(___TEST_ONE___) get_data() version="1" cmd="UNKN"'), |
748 | - call('(___TEST_ONE___) Cleaning buffer - msg = "get_data(): ' |
749 | - 'Invalid packet - unknown command "UNKN""'), |
750 | - call('(___TEST_ONE___) Finished cleaning buffer - 0 bytes dropped')] |
751 | + call('(___TEST_ONE___) Cleaning buffer - msg = "get_data(): Invalid packet - ' |
752 | + 'unknown command "UNKN""'), |
753 | + call('(___TEST_ONE___) Finished cleaning buffer - 0 bytes dropped'), |
754 | + call('(___TEST_ONE___) _send_command(): Nothing to send - returning')] |
755 | |
756 | # WHEN: get_data called with an unknown command |
757 | pjlink.get_data(buff='{prefix}1UNKN=Huh?'.format(prefix=PJLINK_PREFIX)) |
758 | |
759 | === modified file 'tests/openlp_core/projectors/test_projector_pjlink_udp.py' |
760 | --- tests/openlp_core/projectors/test_projector_pjlink_udp.py 2018-04-20 06:04:43 +0000 |
761 | +++ tests/openlp_core/projectors/test_projector_pjlink_udp.py 2018-05-03 14:59:14 +0000 |
762 | @@ -30,37 +30,23 @@ |
763 | import openlp.core.projectors.pjlink |
764 | from openlp.core.projectors.constants import PJLINK_PORT |
765 | |
766 | -from openlp.core.projectors.db import Projector |
767 | -from openlp.core.projectors.pjlink import PJLinkUDP, PJLink |
768 | -from tests.resources.projector.data import TEST1_DATA, TEST2_DATA |
769 | +from openlp.core.projectors.pjlink import PJLinkUDP |
770 | +from tests.resources.projector.data import TEST1_DATA |
771 | |
772 | |
773 | class TestPJLinkBase(TestCase): |
774 | """ |
775 | Tests for the PJLinkUDP class |
776 | """ |
777 | - def setUp(self): |
778 | - """ |
779 | - Setup generic test conditions |
780 | - """ |
781 | - self.test_list = [PJLink(projector=Projector(**TEST1_DATA)), |
782 | - PJLink(projector=Projector(**TEST2_DATA))] |
783 | - |
784 | - def tearDown(self): |
785 | - """ |
786 | - Close generic test condidtions |
787 | - """ |
788 | - self.test_list = None |
789 | - |
790 | @patch.object(openlp.core.projectors.pjlink, 'log') |
791 | def test_get_datagram_data_negative_zero_length(self, mock_log): |
792 | """ |
793 | Test get_datagram when pendingDatagramSize = 0 |
794 | """ |
795 | # GIVEN: Test setup |
796 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
797 | - log_warn_calls = [call('(UDP) No data (-1)')] |
798 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
799 | + pjlink_udp = PJLinkUDP() |
800 | + log_warning_calls = [call('(UDP) No data (-1)')] |
801 | + log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'), |
802 | call('(UDP) get_datagram() - Receiving data')] |
803 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
804 | patch.object(pjlink_udp, 'readDatagram') as mock_read: |
805 | @@ -71,7 +57,7 @@ |
806 | pjlink_udp.get_datagram() |
807 | |
808 | # THEN: Log entries should be made and method returns |
809 | - mock_log.warning.assert_has_calls(log_warn_calls) |
810 | + mock_log.warning.assert_has_calls(log_warning_calls) |
811 | mock_log.debug.assert_has_calls(log_debug_calls) |
812 | |
813 | @patch.object(openlp.core.projectors.pjlink, 'log') |
814 | @@ -80,9 +66,10 @@ |
815 | Test get_datagram when data length = 0 |
816 | """ |
817 | # GIVEN: Test setup |
818 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
819 | - log_warn_calls = [call('(UDP) get_datagram() called when pending data size is 0')] |
820 | - log_debug_calls = [call('(UDP) get_datagram() - Receiving data')] |
821 | + pjlink_udp = PJLinkUDP() |
822 | + log_warning_calls = [call('(UDP) get_datagram() called when pending data size is 0')] |
823 | + log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'), |
824 | + call('(UDP) get_datagram() - Receiving data')] |
825 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram, \ |
826 | patch.object(pjlink_udp, 'readDatagram') as mock_read: |
827 | mock_datagram.return_value = 0 |
828 | @@ -92,7 +79,7 @@ |
829 | pjlink_udp.get_datagram() |
830 | |
831 | # THEN: Log entries should be made and method returns |
832 | - mock_log.warning.assert_has_calls(log_warn_calls) |
833 | + mock_log.warning.assert_has_calls(log_warning_calls) |
834 | mock_log.debug.assert_has_calls(log_debug_calls) |
835 | |
836 | @patch.object(openlp.core.projectors.pjlink, 'log') |
837 | @@ -101,9 +88,9 @@ |
838 | Test get_datagram when pendingDatagramSize = 0 |
839 | """ |
840 | # GIVEN: Test setup |
841 | - pjlink_udp = PJLinkUDP(projector_list=self.test_list) |
842 | - log_warn_calls = [call('(UDP) get_datagram() called when pending data size is 0')] |
843 | - log_debug_calls = [call('(UDP) PJLinkUDP() Initialized'), |
844 | + pjlink_udp = PJLinkUDP() |
845 | + log_warning_calls = [call('(UDP) get_datagram() called when pending data size is 0')] |
846 | + log_debug_calls = [call('(UDP) PJLinkUDP() Initialized for port 4352'), |
847 | call('(UDP) get_datagram() - Receiving data')] |
848 | with patch.object(pjlink_udp, 'pendingDatagramSize') as mock_datagram: |
849 | mock_datagram.return_value = 0 |
850 | @@ -112,5 +99,5 @@ |
851 | pjlink_udp.get_datagram() |
852 | |
853 | # THEN: Log entries should be made and method returns |
854 | - mock_log.warning.assert_has_calls(log_warn_calls) |
855 | + mock_log.warning.assert_has_calls(log_warning_calls) |
856 | mock_log.debug.assert_has_calls(log_debug_calls) |
A question in the code
In future can you put the test results at the bottom of the request as it makes the history easier to read.