Merge lp:~alisonken1/openlp/pjlink2-n into lp:openlp

Proposed by Ken Roberts
Status: Merged
Merged at revision: 2806
Proposed branch: lp:~alisonken1/openlp/pjlink2-n
Merge into: lp:openlp
Diff against target: 3657 lines (+1549/-1305)
7 files modified
openlp/core/projectors/constants.py (+296/-224)
openlp/core/projectors/manager.py (+37/-33)
openlp/core/projectors/pjlink.py (+114/-97)
tests/functional/openlp_core/projectors/test_projector_constants.py (+39/-0)
tests/functional/openlp_core/projectors/test_projector_pjlink_base.py (+3/-4)
tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py (+183/-170)
tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py (+877/-777)
To merge this branch: bzr merge lp:~alisonken1/openlp/pjlink2-n
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Raoul Snyman Approve
Review via email: mp+335646@code.launchpad.net

This proposal supersedes a proposal from 2017-12-26.

Commit message

PJLink 2 update N

Description of the change

--------------------------------------------------------------------------------
lp:~alisonken1/openlp/pjlink2-n (revision 2806)
https://ci.openlp.io/job/Branch-01-Pull/2409/ [SUCCESS]
https://ci.openlp.io/job/Branch-02a-Linux-Tests/2310/ [SUCCESS]
https://ci.openlp.io/job/Branch-02b-macOS-Tests/105/ [SUCCESS]
https://ci.openlp.io/job/Branch-03a-Build-Source/29/ [SUCCESS]
https://ci.openlp.io/job/Branch-03b-Build-macOS/28/ [SUCCESS]
https://ci.openlp.io/job/Branch-04a-Code-Analysis/1491/ [SUCCESS]
https://ci.openlp.io/job/Branch-04b-Test-Coverage/1304/ [SUCCESS]
https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/256/ [FAILURE]

Large diff fixing projector tests

- Update some comments
- Some PJLink code fixes/restructuring
- Restructure some projector tests for proper mocking
- Fix manager.py and pjlink.py for changes to constants.py
- Fix test_projector_pjlink_routing.py for proper mocking and restructuring
- Renamed test_process_command_invalid to test_get_data_unknown_command
- Added test to verify assigned E_*/S_* codes are in STATUS_CODE and STATUS_MSG
- Added missing status/error codes to STATUS_MSG
- Added error checks to process_inpt
- Deleted unneeded test(s)
- More assert cleanups
- Merge trunk to fix conflicts

Updates to constants.py include:
    - Reordered dictionaries and lists into alphabetical order
    - Added PJLINK_ERST_LIST
    - Added S_NETWORK_IDLE code (for future)
    - Added PJLINK_STATUS list
    - Move S_QSOCKET_STATUS to QSOCKET_STATE
    - Move STATUS_STRING to STATUS_CODE
    - Move PJLINK_CLASS, PJLINK_SUFFIX, and PJLINK_PREFIX from pjlink.py to constants.py
    - Change CONNECTION_ERRORS from a dictionary to a list
    - Change QSOCKET_STATE to map QAbstractSocket.state() to local status codes
    - Merge ERROR_MSG with STATUS_MSG
    - Merge ERROR_STRING into STATUS_CODE
    - Clean out unused portion of PJLINK_ERST_STATUS
    - Clean out unused portion of PJLINK_POWR_STATUS
    - Clean out unused portion of QSOCKET_STATUS

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Some questions and old style asserts remain!

review: Needs Fixing
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Looks good and my issues have been resolved,
Unable to test code!

review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Looks OK to me.

review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Actually, I'm getting a conflict in trunk, can you just merge from trunk and resolve that conflict please?

review: Needs Resubmitting
Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve
Revision history for this message
Tim Bentley (trb143) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/projectors/constants.py'
2--- openlp/core/projectors/constants.py 2017-12-29 09:15:48 +0000
3+++ openlp/core/projectors/constants.py 2018-01-03 05:54:24 +0000
4@@ -32,9 +32,128 @@
5 # Set common constants.
6 CR = chr(0x0D) # \r
7 LF = chr(0x0A) # \n
8+PJLINK_CLASS = '1' # Default to class 1 until we query the projector
9+PJLINK_MAX_PACKET = 136
10+PJLINK_PREFIX = '%'
11 PJLINK_PORT = 4352
12-TIMEOUT = 30.0
13-PJLINK_MAX_PACKET = 136
14+PJLINK_SUFFIX = CR
15+PJLINK_TIMEOUT = 30.0
16+
17+# Error and status codes
18+S_OK = E_OK = 0 # E_OK included since I sometimes forget
19+
20+# Error codes. Start at 200 so we don't duplicate system error codes.
21+E_GENERAL = 200 # Unknown error
22+E_NOT_CONNECTED = 201
23+E_UNDEFINED = 202 # PJLink ERR1
24+E_PARAMETER = 203 # PJLink ERR2
25+E_UNAVAILABLE = 204 # PJLink ERR3
26+E_PROJECTOR = 205 # PJLink ERR4
27+E_AUTHENTICATION = 206 # PJLink ERRA
28+E_NO_AUTHENTICATION = 207 # PJLink authentication mismatch between projector and program
29+E_PREFIX = 208 # PJLink invalid prefix for packet
30+E_CLASS = 209 # PJLink class version mismatch
31+E_INVALID_DATA = 210
32+E_WARN = 211
33+E_ERROR = 212
34+E_FAN = 213
35+E_LAMP = 214
36+E_TEMP = 215
37+E_COVER = 216
38+E_FILTER = 217
39+E_UNKNOWN = 218
40+
41+# Remap Qt socket error codes to local error codes
42+E_CONNECTION_REFUSED = 230
43+E_REMOTE_HOST_CLOSED_CONNECTION = 231
44+E_HOST_NOT_FOUND = 232
45+E_SOCKET_ACCESS = 233
46+E_SOCKET_RESOURCE = 234
47+E_SOCKET_TIMEOUT = 235
48+E_DATAGRAM_TOO_LARGE = 236
49+E_NETWORK = 237
50+E_ADDRESS_IN_USE = 238
51+E_SOCKET_ADDRESS_NOT_AVAILABLE = 239
52+E_UNSUPPORTED_SOCKET_OPERATION = 240
53+E_PROXY_AUTHENTICATION_REQUIRED = 241
54+E_SLS_HANDSHAKE_FAILED = 242
55+E_UNFINISHED_SOCKET_OPERATION = 243
56+E_PROXY_CONNECTION_REFUSED = 244
57+E_PROXY_CONNECTION_CLOSED = 245
58+E_PROXY_CONNECTION_TIMEOUT = 246
59+E_PROXY_NOT_FOUND = 247
60+E_PROXY_PROTOCOL = 248
61+E_UNKNOWN_SOCKET_ERROR = 249
62+
63+# Status codes start at 300
64+
65+# Remap Qt socket states to local status codes
66+S_NOT_CONNECTED = 300
67+S_HOST_LOOKUP = 301
68+S_CONNECTING = 302
69+S_CONNECTED = 303
70+S_BOUND = 304
71+S_LISTENING = 305 # Listed as internal use only in QAbstractSocket
72+S_CLOSING = 306
73+
74+# Projector states
75+S_INITIALIZE = 310
76+S_STATUS = 311
77+S_OFF = 312
78+S_STANDBY = 313
79+S_WARMUP = 314
80+S_ON = 315
81+S_COOLDOWN = 316
82+S_INFO = 317
83+
84+# Information that does not affect status
85+S_NETWORK_IDLE = 400
86+S_NETWORK_SENDING = 401
87+S_NETWORK_RECEIVING = 402
88+
89+# Map PJlink errors to local status
90+PJLINK_ERRORS = {
91+ 'ERRA': E_AUTHENTICATION, # Authentication error
92+ 'ERR1': E_UNDEFINED, # Undefined command error
93+ 'ERR2': E_PARAMETER, # Invalid parameter error
94+ 'ERR3': E_UNAVAILABLE, # Projector busy
95+ 'ERR4': E_PROJECTOR, # Projector or display failure
96+ E_AUTHENTICATION: 'ERRA',
97+ E_UNDEFINED: 'ERR1',
98+ E_PARAMETER: 'ERR2',
99+ E_UNAVAILABLE: 'ERR3',
100+ E_PROJECTOR: 'ERR4'
101+}
102+
103+# Map QAbstractSocketState enums to local status
104+QSOCKET_STATE = {
105+ 0: S_NOT_CONNECTED, # 'UnconnectedState',
106+ 1: S_HOST_LOOKUP, # 'HostLookupState',
107+ 2: S_CONNECTING, # 'ConnectingState',
108+ 3: S_CONNECTED, # 'ConnectedState',
109+ 4: S_BOUND, # 'BoundState',
110+ 5: S_LISTENING, # 'ListeningState' - Noted as "Internal Use Only" on Qt website
111+ 6: S_CLOSING, # 'ClosingState',
112+ S_NOT_CONNECTED: 0,
113+ S_HOST_LOOKUP: 1,
114+ S_CONNECTING: 2,
115+ S_CONNECTED: 3,
116+ S_BOUND: 4,
117+ S_LISTENING: 5,
118+ S_CLOSING: 6
119+}
120+
121+PROJECTOR_STATE = [
122+ S_INITIALIZE,
123+ S_STATUS,
124+ S_OFF,
125+ S_STANDBY,
126+ S_WARMUP,
127+ S_ON,
128+ S_COOLDOWN,
129+ S_INFO
130+]
131+
132 # NOTE: Changed format to account for some commands are both class 1 and 2
133 PJLINK_VALID_CMD = {
134 'ACKN': {'version': ['2', ],
135@@ -144,227 +263,140 @@
136 }
137 }
138
139-# QAbstractSocketState enums converted to string
140-S_QSOCKET_STATE = {
141- 0: 'QSocketState - UnconnectedState',
142- 1: 'QSocketState - HostLookupState',
143- 2: 'QSocketState - ConnectingState',
144- 3: 'QSocketState - ConnectedState',
145- 4: 'QSocketState - BoundState',
146- 5: 'QSocketState - ListeningState (internal use only)',
147- 6: 'QSocketState - ClosingState',
148- 'UnconnectedState': 0,
149- 'HostLookupState': 1,
150- 'ConnectingState': 2,
151- 'ConnectedState': 3,
152- 'BoundState': 4,
153- 'ListeningState': 5,
154- 'ClosingState': 6
155-}
156-
157-# Error and status codes
158-S_OK = E_OK = 0 # E_OK included since I sometimes forget
159-# Error codes. Start at 200 so we don't duplicate system error codes.
160-E_GENERAL = 200 # Unknown error
161-E_NOT_CONNECTED = 201
162-E_FAN = 202
163-E_LAMP = 203
164-E_TEMP = 204
165-E_COVER = 205
166-E_FILTER = 206
167-E_NO_AUTHENTICATION = 207 # PIN set and no authentication set on projector
168-E_UNDEFINED = 208 # ERR1
169-E_PARAMETER = 209 # ERR2
170-E_UNAVAILABLE = 210 # ERR3
171-E_PROJECTOR = 211 # ERR4
172-E_INVALID_DATA = 212
173-E_WARN = 213
174-E_ERROR = 214
175-E_AUTHENTICATION = 215 # ERRA
176-E_CLASS = 216
177-E_PREFIX = 217
178-
179-# Remap Qt socket error codes to projector error codes
180-E_CONNECTION_REFUSED = 230
181-E_REMOTE_HOST_CLOSED_CONNECTION = 231
182-E_HOST_NOT_FOUND = 232
183-E_SOCKET_ACCESS = 233
184-E_SOCKET_RESOURCE = 234
185-E_SOCKET_TIMEOUT = 235
186-E_DATAGRAM_TOO_LARGE = 236
187-E_NETWORK = 237
188-E_ADDRESS_IN_USE = 238
189-E_SOCKET_ADDRESS_NOT_AVAILABLE = 239
190-E_UNSUPPORTED_SOCKET_OPERATION = 240
191-E_PROXY_AUTHENTICATION_REQUIRED = 241
192-E_SLS_HANDSHAKE_FAILED = 242
193-E_UNFINISHED_SOCKET_OPERATION = 243
194-E_PROXY_CONNECTION_REFUSED = 244
195-E_PROXY_CONNECTION_CLOSED = 245
196-E_PROXY_CONNECTION_TIMEOUT = 246
197-E_PROXY_NOT_FOUND = 247
198-E_PROXY_PROTOCOL = 248
199-E_UNKNOWN_SOCKET_ERROR = -1
200-
201-# Status codes start at 300
202-S_NOT_CONNECTED = 300
203-S_CONNECTING = 301
204-S_CONNECTED = 302
205-S_INITIALIZE = 303
206-S_STATUS = 304
207-S_OFF = 305
208-S_STANDBY = 306
209-S_WARMUP = 307
210-S_ON = 308
211-S_COOLDOWN = 309
212-S_INFO = 310
213-
214-# Information that does not affect status
215-S_NETWORK_SENDING = 400
216-S_NETWORK_RECEIVED = 401
217-
218-CONNECTION_ERRORS = {
219- E_NOT_CONNECTED, E_NO_AUTHENTICATION, E_AUTHENTICATION, E_CLASS,
220- E_PREFIX, E_CONNECTION_REFUSED, E_REMOTE_HOST_CLOSED_CONNECTION,
221- E_HOST_NOT_FOUND, E_SOCKET_ACCESS, E_SOCKET_RESOURCE, E_SOCKET_TIMEOUT,
222- E_DATAGRAM_TOO_LARGE, E_NETWORK, E_ADDRESS_IN_USE, E_SOCKET_ADDRESS_NOT_AVAILABLE,
223- E_UNSUPPORTED_SOCKET_OPERATION, E_PROXY_AUTHENTICATION_REQUIRED,
224- E_SLS_HANDSHAKE_FAILED, E_UNFINISHED_SOCKET_OPERATION, E_PROXY_CONNECTION_REFUSED,
225- E_PROXY_CONNECTION_CLOSED, E_PROXY_CONNECTION_TIMEOUT, E_PROXY_NOT_FOUND,
226- E_PROXY_PROTOCOL, E_UNKNOWN_SOCKET_ERROR
227-}
228-
229-PJLINK_ERRORS = {
230- 'ERRA': E_AUTHENTICATION, # Authentication error
231- 'ERR1': E_UNDEFINED, # Undefined command error
232- 'ERR2': E_PARAMETER, # Invalid parameter error
233- 'ERR3': E_UNAVAILABLE, # Projector busy
234- 'ERR4': E_PROJECTOR, # Projector or display failure
235- E_AUTHENTICATION: 'ERRA',
236- E_UNDEFINED: 'ERR1',
237- E_PARAMETER: 'ERR2',
238- E_UNAVAILABLE: 'ERR3',
239- E_PROJECTOR: 'ERR4'
240-}
241-
242-# Map error/status codes to string
243-ERROR_STRING = {
244- 0: 'S_OK',
245+CONNECTION_ERRORS = [
246+ E_ADDRESS_IN_USE,
247+ E_CONNECTION_REFUSED,
248+ E_DATAGRAM_TOO_LARGE,
249+ E_HOST_NOT_FOUND,
250+ E_NETWORK,
251+ E_NOT_CONNECTED,
252+ E_PROXY_AUTHENTICATION_REQUIRED,
253+ E_PROXY_CONNECTION_CLOSED,
254+ E_PROXY_CONNECTION_REFUSED,
255+ E_PROXY_CONNECTION_TIMEOUT,
256+ E_PROXY_NOT_FOUND,
257+ E_PROXY_PROTOCOL,
258+ E_REMOTE_HOST_CLOSED_CONNECTION,
259+ E_SLS_HANDSHAKE_FAILED,
260+ E_SOCKET_ACCESS,
261+ E_SOCKET_ADDRESS_NOT_AVAILABLE,
262+ E_SOCKET_RESOURCE,
263+ E_SOCKET_TIMEOUT,
264+ E_UNFINISHED_SOCKET_OPERATION,
265+ E_UNKNOWN_SOCKET_ERROR,
266+ E_UNSUPPORTED_SOCKET_OPERATION
267+]
268+
269+PROJECTOR_ERRORS = [
270+ E_AUTHENTICATION,
271+ E_CLASS,
272+ E_INVALID_DATA,
273+ E_NO_AUTHENTICATION,
274+ E_PARAMETER,
275+ E_PREFIX,
276+ E_PROJECTOR,
277+ E_UNAVAILABLE,
278+ E_UNDEFINED,
279+ E_UNKNOWN
280+]
281+
282+# Show status code as string
283+STATUS_CODE = {
284+ E_ADDRESS_IN_USE: 'E_ADDRESS_IN_USE',
285+ E_AUTHENTICATION: 'E_AUTHENTICATION',
286+ E_CLASS: 'E_CLASS',
287+ E_CONNECTION_REFUSED: 'E_CONNECTION_REFUSED',
288+ E_COVER: 'E_COVER',
289+ E_DATAGRAM_TOO_LARGE: 'E_DATAGRAM_TOO_LARGE',
290+ E_ERROR: 'E_ERROR',
291+ E_FAN: 'E_FAN',
292+ E_FILTER: 'E_FILTER',
293 E_GENERAL: 'E_GENERAL',
294- E_NOT_CONNECTED: 'E_NOT_CONNECTED',
295- E_FAN: 'E_FAN',
296+ E_HOST_NOT_FOUND: 'E_HOST_NOT_FOUND',
297+ E_INVALID_DATA: 'E_INVALID_DATA',
298 E_LAMP: 'E_LAMP',
299- E_TEMP: 'E_TEMP',
300- E_COVER: 'E_COVER',
301- E_FILTER: 'E_FILTER',
302- E_AUTHENTICATION: 'E_AUTHENTICATION',
303+ E_NETWORK: 'E_NETWORK',
304 E_NO_AUTHENTICATION: 'E_NO_AUTHENTICATION',
305- E_UNDEFINED: 'E_UNDEFINED',
306+ E_NOT_CONNECTED: 'E_NOT_CONNECTED',
307 E_PARAMETER: 'E_PARAMETER',
308- E_UNAVAILABLE: 'E_UNAVAILABLE',
309+ E_PREFIX: 'E_PREFIX',
310 E_PROJECTOR: 'E_PROJECTOR',
311- E_INVALID_DATA: 'E_INVALID_DATA',
312- E_WARN: 'E_WARN',
313- E_ERROR: 'E_ERROR',
314- E_CLASS: 'E_CLASS',
315- E_PREFIX: 'E_PREFIX', # Last projector error
316- E_CONNECTION_REFUSED: 'E_CONNECTION_REFUSED', # First QtSocket error
317+ E_PROXY_AUTHENTICATION_REQUIRED: 'E_PROXY_AUTHENTICATION_REQUIRED',
318+ E_PROXY_CONNECTION_CLOSED: 'E_PROXY_CONNECTION_CLOSED',
319+ E_PROXY_CONNECTION_REFUSED: 'E_PROXY_CONNECTION_REFUSED',
320+ E_PROXY_CONNECTION_TIMEOUT: 'E_PROXY_CONNECTION_TIMEOUT',
321+ E_PROXY_NOT_FOUND: 'E_PROXY_NOT_FOUND',
322+ E_PROXY_PROTOCOL: 'E_PROXY_PROTOCOL',
323 E_REMOTE_HOST_CLOSED_CONNECTION: 'E_REMOTE_HOST_CLOSED_CONNECTION',
324- E_HOST_NOT_FOUND: 'E_HOST_NOT_FOUND',
325+ E_SLS_HANDSHAKE_FAILED: 'E_SLS_HANDSHAKE_FAILED',
326 E_SOCKET_ACCESS: 'E_SOCKET_ACCESS',
327+ E_SOCKET_ADDRESS_NOT_AVAILABLE: 'E_SOCKET_ADDRESS_NOT_AVAILABLE',
328 E_SOCKET_RESOURCE: 'E_SOCKET_RESOURCE',
329 E_SOCKET_TIMEOUT: 'E_SOCKET_TIMEOUT',
330- E_DATAGRAM_TOO_LARGE: 'E_DATAGRAM_TOO_LARGE',
331- E_NETWORK: 'E_NETWORK',
332- E_ADDRESS_IN_USE: 'E_ADDRESS_IN_USE',
333- E_SOCKET_ADDRESS_NOT_AVAILABLE: 'E_SOCKET_ADDRESS_NOT_AVAILABLE',
334+ E_TEMP: 'E_TEMP',
335+ E_UNAVAILABLE: 'E_UNAVAILABLE',
336+ E_UNDEFINED: 'E_UNDEFINED',
337+ E_UNFINISHED_SOCKET_OPERATION: 'E_UNFINISHED_SOCKET_OPERATION',
338+ E_UNKNOWN: 'E_UNKNOWN',
339+ E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR',
340 E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION',
341- E_PROXY_AUTHENTICATION_REQUIRED: 'E_PROXY_AUTHENTICATION_REQUIRED',
342- E_SLS_HANDSHAKE_FAILED: 'E_SLS_HANDSHAKE_FAILED',
343- E_UNFINISHED_SOCKET_OPERATION: 'E_UNFINISHED_SOCKET_OPERATION',
344- E_PROXY_CONNECTION_REFUSED: 'E_PROXY_CONNECTION_REFUSED',
345- E_PROXY_CONNECTION_CLOSED: 'E_PROXY_CONNECTION_CLOSED',
346- E_PROXY_CONNECTION_TIMEOUT: 'E_PROXY_CONNECTION_TIMEOUT',
347- E_PROXY_NOT_FOUND: 'E_PROXY_NOT_FOUND',
348- E_PROXY_PROTOCOL: 'E_PROXY_PROTOCOL',
349- E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR'
350-}
351-
352-STATUS_STRING = {
353+ E_WARN: 'E_WARN',
354+ S_BOUND: 'S_BOUND',
355+ S_COOLDOWN: 'S_COOLDOWN',
356+ S_CLOSING: 'S_CLOSING',
357+ S_CONNECTED: 'S_CONNECTED',
358+ S_CONNECTING: 'S_CONNECTING',
359+ S_HOST_LOOKUP: 'S_HOST_LOOKUP',
360+ S_INFO: 'S_INFO',
361+ S_INITIALIZE: 'S_INITIALIZE',
362+ S_LISTENING: 'S_LISTENING',
363+ S_NETWORK_RECEIVING: 'S_NETWORK_RECEIVING',
364+ S_NETWORK_SENDING: 'S_NETWORK_SENDING',
365+ S_NETWORK_IDLE: 'S_NETWORK_IDLE',
366 S_NOT_CONNECTED: 'S_NOT_CONNECTED',
367- S_CONNECTING: 'S_CONNECTING',
368- S_CONNECTED: 'S_CONNECTED',
369- S_STATUS: 'S_STATUS',
370 S_OFF: 'S_OFF',
371- S_INITIALIZE: 'S_INITIALIZE',
372+ S_OK: 'S_OK', # S_OK or E_OK
373+ S_ON: 'S_ON',
374 S_STANDBY: 'S_STANDBY',
375+ S_STATUS: 'S_STATUS',
376 S_WARMUP: 'S_WARMUP',
377- S_ON: 'S_ON',
378- S_COOLDOWN: 'S_COOLDOWN',
379- S_INFO: 'S_INFO',
380- S_NETWORK_SENDING: 'S_NETWORK_SENDING',
381- S_NETWORK_RECEIVED: 'S_NETWORK_RECEIVED'
382 }
383
384-# Map error/status codes to message strings
385-ERROR_MSG = {
386- E_OK: translate('OpenLP.ProjectorConstants', 'OK'), # E_OK | S_OK
387- E_GENERAL: translate('OpenLP.ProjectorConstants', 'General projector error'),
388- E_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not connected error'),
389- E_LAMP: translate('OpenLP.ProjectorConstants', 'Lamp error'),
390- E_FAN: translate('OpenLP.ProjectorConstants', 'Fan error'),
391- E_TEMP: translate('OpenLP.ProjectorConstants', 'High temperature detected'),
392- E_COVER: translate('OpenLP.ProjectorConstants', 'Cover open detected'),
393- E_FILTER: translate('OpenLP.ProjectorConstants', 'Check filter'),
394- E_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'Authentication Error'),
395- E_UNDEFINED: translate('OpenLP.ProjectorConstants', 'Undefined Command'),
396- E_PARAMETER: translate('OpenLP.ProjectorConstants', 'Invalid Parameter'),
397- E_UNAVAILABLE: translate('OpenLP.ProjectorConstants', 'Projector Busy'),
398- E_PROJECTOR: translate('OpenLP.ProjectorConstants', 'Projector/Display Error'),
399- E_INVALID_DATA: translate('OpenLP.ProjectorConstants', 'Invalid packet received'),
400- E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
401- E_ERROR: translate('OpenLP.ProjectorConstants', 'Error condition detected'),
402- E_CLASS: translate('OpenLP.ProjectorConstants', 'PJLink class not supported'),
403- E_PREFIX: translate('OpenLP.ProjectorConstants', 'Invalid prefix character'),
404+# Map status codes to message strings
405+STATUS_MSG = {
406+ E_ADDRESS_IN_USE: translate('OpenLP.ProjectorConstants',
407+ 'The address specified with socket.bind() '
408+ 'is already in use and was set to be exclusive'),
409+ E_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERRA: Authentication Error"'),
410 E_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
411 'The connection was refused by the peer (or timed out)'),
412- E_REMOTE_HOST_CLOSED_CONNECTION: translate('OpenLP.ProjectorConstants',
413- 'The remote host closed the connection'),
414+ E_COVER: translate('OpenLP.ProjectorConstants', 'Projector cover open detected'),
415+ E_CLASS: translate('OpenLP.ProjectorConstants', 'PJLink class not supported'),
416+ E_DATAGRAM_TOO_LARGE: translate('OpenLP.ProjectorConstants',
417+ "The datagram was larger than the operating system's limit"),
418+ E_ERROR: translate('OpenLP.ProjectorConstants', 'Error condition detected'),
419+ E_FAN: translate('OpenLP.ProjectorConstants', 'Projector fan error'),
420+ E_FILTER: translate('OpenLP.ProjectorConstants', 'Projector check filter'),
421+ E_GENERAL: translate('OpenLP.ProjectorConstants', 'General projector error'),
422 E_HOST_NOT_FOUND: translate('OpenLP.ProjectorConstants', 'The host address was not found'),
423- E_SOCKET_ACCESS: translate('OpenLP.ProjectorConstants',
424- 'The socket operation failed because the application '
425- 'lacked the required privileges'),
426- E_SOCKET_RESOURCE: translate('OpenLP.ProjectorConstants',
427- 'The local system ran out of resources (e.g., too many sockets)'),
428- E_SOCKET_TIMEOUT: translate('OpenLP.ProjectorConstants',
429- 'The socket operation timed out'),
430- E_DATAGRAM_TOO_LARGE: translate('OpenLP.ProjectorConstants',
431- 'The datagram was larger than the operating system\'s limit'),
432+ E_INVALID_DATA: translate('OpenLP.ProjectorConstants', 'PJLink invalid packet received'),
433+ E_LAMP: translate('OpenLP.ProjectorConstants', 'Projector lamp error'),
434 E_NETWORK: translate('OpenLP.ProjectorConstants',
435 'An error occurred with the network (Possibly someone pulled the plug?)'),
436- E_ADDRESS_IN_USE: translate('OpenLP.ProjectorConstants',
437- 'The address specified with socket.bind() '
438- 'is already in use and was set to be exclusive'),
439- E_SOCKET_ADDRESS_NOT_AVAILABLE: translate('OpenLP.ProjectorConstants',
440- 'The address specified to socket.bind() '
441- 'does not belong to the host'),
442- E_UNSUPPORTED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
443- 'The requested socket operation is not supported by the local '
444- 'operating system (e.g., lack of IPv6 support)'),
445+ E_NO_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'PJlink authentication Mismatch Error'),
446+ E_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Projector not connected error'),
447+ E_PARAMETER: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR2: Invalid Parameter"'),
448+ E_PREFIX: translate('OpenLP.ProjectorConstants', 'PJLink Invalid prefix character'),
449+ E_PROJECTOR: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR4: Projector/Display Error"'),
450 E_PROXY_AUTHENTICATION_REQUIRED: translate('OpenLP.ProjectorConstants',
451 'The socket is using a proxy, '
452 'and the proxy requires authentication'),
453- E_SLS_HANDSHAKE_FAILED: translate('OpenLP.ProjectorConstants',
454- 'The SSL/TLS handshake failed'),
455- E_UNFINISHED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
456- 'The last operation attempted has not finished yet '
457- '(still in progress in the background)'),
458+ E_PROXY_CONNECTION_CLOSED: translate('OpenLP.ProjectorConstants',
459+ 'The connection to the proxy server was closed unexpectedly '
460+ '(before the connection to the final peer was established)'),
461 E_PROXY_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
462 'Could not contact the proxy server because the connection '
463 'to that server was denied'),
464- E_PROXY_CONNECTION_CLOSED: translate('OpenLP.ProjectorConstants',
465- 'The connection to the proxy server was closed unexpectedly '
466- '(before the connection to the final peer was established)'),
467 E_PROXY_CONNECTION_TIMEOUT: translate('OpenLP.ProjectorConstants',
468 'The connection to the proxy server timed out or the proxy '
469 'server stopped responding in the authentication phase.'),
470@@ -373,51 +405,91 @@
471 E_PROXY_PROTOCOL: translate('OpenLP.ProjectorConstants',
472 'The connection negotiation with the proxy server failed because the '
473 'response from the proxy server could not be understood'),
474- E_UNKNOWN_SOCKET_ERROR: translate('OpenLP.ProjectorConstants', 'An unidentified error occurred'),
475- S_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not connected'),
476+ E_REMOTE_HOST_CLOSED_CONNECTION: translate('OpenLP.ProjectorConstants',
477+ 'The remote host closed the connection'),
478+ E_SLS_HANDSHAKE_FAILED: translate('OpenLP.ProjectorConstants',
479+ 'The SSL/TLS handshake failed'),
480+ E_SOCKET_ADDRESS_NOT_AVAILABLE: translate('OpenLP.ProjectorConstants',
481+ 'The address specified to socket.bind() '
482+ 'does not belong to the host'),
483+ E_SOCKET_ACCESS: translate('OpenLP.ProjectorConstants',
484+ 'The socket operation failed because the application '
485+ 'lacked the required privileges'),
486+ E_SOCKET_RESOURCE: translate('OpenLP.ProjectorConstants',
487+ 'The local system ran out of resources (e.g., too many sockets)'),
488+ E_SOCKET_TIMEOUT: translate('OpenLP.ProjectorConstants',
489+ 'The socket operation timed out'),
490+ E_TEMP: translate('OpenLP.ProjectorConstants', 'Projector high temperature detected'),
491+ E_UNAVAILABLE: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR3: Busy"'),
492+ E_UNDEFINED: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR1: Undefined Command"'),
493+ E_UNFINISHED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
494+ 'The last operation attempted has not finished yet '
495+ '(still in progress in the background)'),
496+ E_UNKNOWN: translate('OpenLP.ProjectorConstants', 'Unknown condiction detected'),
497+ E_UNKNOWN_SOCKET_ERROR: translate('OpenLP.ProjectorConstants', 'An unidentified socket error occurred'),
498+ E_UNSUPPORTED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
499+ 'The requested socket operation is not supported by the local '
500+ 'operating system (e.g., lack of IPv6 support)'),
501+ E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
502+ S_BOUND: translate('OpenLP.ProjectorConstants', 'Socket is bount to an address or port'),
503+ S_CLOSING: translate('OpenLP.ProjectorConstants', 'Socket is about to close'),
504+ S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),
505 S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'),
506- S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),
507- S_STATUS: translate('OpenLP.ProjectorConstants', 'Getting status'),
508+ S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),
509+ S_HOST_LOOKUP: translate('OpenLP.ProjectorConstants', 'Performing a host name lookup'),
510+ S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),
511+ S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),
512+ S_LISTENING: translate('OpenLP.ProjectorConstants', 'Socket it listening (internal use only)'),
513+ S_NETWORK_IDLE: translate('OpenLP.ProjectorConstants', 'No network activity at this time'),
514+ S_NETWORK_RECEIVING: translate('OpenLP.ProjectorConstants', 'Received data'),
515+ S_NETWORK_SENDING: translate('OpenLP.ProjectorConstants', 'Sending data'),
516+ S_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not Connected'),
517 S_OFF: translate('OpenLP.ProjectorConstants', 'Off'),
518- S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),
519+ S_OK: translate('OpenLP.ProjectorConstants', 'OK'),
520+ S_ON: translate('OpenLP.ProjectorConstants', 'Power is on'),
521 S_STANDBY: translate('OpenLP.ProjectorConstants', 'Power in standby'),
522+ S_STATUS: translate('OpenLP.ProjectorConstants', 'Getting status'),
523 S_WARMUP: translate('OpenLP.ProjectorConstants', 'Warmup in progress'),
524- S_ON: translate('OpenLP.ProjectorConstants', 'Power is on'),
525- S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),
526- S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),
527- S_NETWORK_SENDING: translate('OpenLP.ProjectorConstants', 'Sending data'),
528- S_NETWORK_RECEIVED: translate('OpenLP.ProjectorConstants', 'Received data')
529-}
530-
531-# Map ERST return code positions to equipment
532+}
533+
534+# Map ERST reply positions to equipment
535+PJLINK_ERST_LIST = {
536+ "FAN": translate('OpenLP.PJLink', 'Fan'),
537+ "LAMP": translate('OpenLP.PJLink', 'Lamp'),
538+ "TEMP": translate('OpenLP.PJLink', 'Temperature'),
539+ "COVER": translate('OpenLP.PJLink', 'Cover'),
540+ "FILTER": translate('OpenLP.PJLink', 'Filter'),
541+ "OTHER": translate('OpenPL.PJLink', 'Other')
542+}
543+
544+# Map projector item to ERST data position
545 PJLINK_ERST_DATA = {
546- 'DATA_LENGTH': 6,
547+ 'DATA_LENGTH': 6, # Zero based so enums are 0-5
548+ 'FAN': 0,
549+ 'LAMP': 1,
550+ 'TEMP': 2,
551+ 'COVER': 3,
552+ 'FILTER': 4,
553+ 'OTHER': 5,
554 0: 'FAN',
555 1: 'LAMP',
556 2: 'TEMP',
557 3: 'COVER',
558 4: 'FILTER',
559- 5: 'OTHER',
560- 'FAN': 0,
561- 'LAMP': 1,
562- 'TEMP': 2,
563- 'COVER': 3,
564- 'FILTER': 4,
565- 'OTHER': 5
566+ 5: 'OTHER'
567 }
568
569-# Map for ERST return codes to string
570+# Map ERST reply codes to string
571 PJLINK_ERST_STATUS = {
572- '0': 'OK',
573- '1': ERROR_STRING[E_WARN],
574- '2': ERROR_STRING[E_ERROR],
575- 'OK': '0',
576- E_OK: '0',
577+ '0': S_OK,
578+ '1': E_WARN,
579+ '2': E_ERROR,
580+ S_OK: '0',
581 E_WARN: '1',
582 E_ERROR: '2'
583 }
584
585-# Map for POWR return codes to status code
586+# Map POWR return codes to status code
587 PJLINK_POWR_STATUS = {
588 '0': S_STANDBY,
589 '1': S_ON,
590
591=== modified file 'openlp/core/projectors/manager.py'
592--- openlp/core/projectors/manager.py 2017-12-29 09:15:48 +0000
593+++ openlp/core/projectors/manager.py 2018-01-03 05:54:24 +0000
594@@ -35,9 +35,25 @@
595 from openlp.core.common.settings import Settings
596 from openlp.core.lib.ui import create_widget_action
597 from openlp.core.projectors import DialogSourceStyle
598-from openlp.core.projectors.constants import ERROR_MSG, ERROR_STRING, E_AUTHENTICATION, E_ERROR, \
599- E_NETWORK, E_NOT_CONNECTED, E_UNKNOWN_SOCKET_ERROR, STATUS_STRING, S_CONNECTED, S_CONNECTING, S_COOLDOWN, \
600- S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP
601+from openlp.core.projectors.constants import \
602+ E_AUTHENTICATION, \
603+ E_ERROR, \
604+ E_NETWORK, \
605+ E_NOT_CONNECTED, \
606+ E_UNKNOWN_SOCKET_ERROR, \
607+ S_CONNECTED, \
608+ S_CONNECTING, \
609+ S_COOLDOWN, \
610+ S_INITIALIZE, \
611+ S_NOT_CONNECTED, \
612+ S_OFF, \
613+ S_ON, \
614+ S_STANDBY, \
615+ S_WARMUP, \
616+ STATUS_CODE, \
617+ STATUS_MSG, \
618+ QSOCKET_STATE
619+
620 from openlp.core.projectors.db import ProjectorDB
621 from openlp.core.projectors.editform import ProjectorEditForm
622 from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
623@@ -440,11 +456,12 @@
624 :param opt: Needed by PyQt5
625 """
626 projector = item.data(QtCore.Qt.UserRole)
627- if projector.link.state() != projector.link.ConnectedState:
628+ if QSOCKET_STATE[projector.link.state()] != S_CONNECTED:
629 try:
630+ log.debug('ProjectorManager: Calling connect_to_host() on "{ip}"'.format(ip=projector.link.ip))
631 projector.link.connect_to_host()
632 except:
633- pass
634+ log.debug('ProjectorManager: "{ip}" already connected - skipping'.format(ip=projector.link.ip))
635 return
636
637 def on_connect_projector(self, opt=None):
638@@ -647,7 +664,7 @@
639 'Other info'),
640 data=projector.link.other_info)
641 message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Power status'),
642- data=ERROR_MSG[projector.link.power])
643+ data=STATUS_MSG[projector.link.power])
644 message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Shutter is'),
645 data=translate('OpenLP.ProjectorManager', 'Closed')
646 if projector.link.shutter
647@@ -692,7 +709,7 @@
648 else:
649 message += '<b>{data}</b>'.format(data=translate('OpenLP.ProjectorManager', 'Current errors/warnings'))
650 for (key, val) in projector.link.projector_errors.items():
651- message += '<b>{key}</b>: {data}<br />'.format(key=key, data=ERROR_MSG[val])
652+ message += '<b>{key}</b>: {data}<br />'.format(key=key, data=STATUS_MSG[val])
653 QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message)
654
655 def _add_projector(self, projector):
656@@ -817,31 +834,18 @@
657 if ip == list_item.link.ip:
658 item = list_item
659 break
660- message = translate('OpenLP.ProjectorManager', 'No message') if msg is None else msg
661- if status in STATUS_STRING:
662- status_code = STATUS_STRING[status]
663- message = ERROR_MSG[status] if msg is None else msg
664- elif status in ERROR_STRING:
665- status_code = ERROR_STRING[status]
666- message = ERROR_MSG[status] if msg is None else msg
667- else:
668- status_code = status
669- message = ERROR_MSG[status] if msg is None else msg
670- log.debug('({name}) updateStatus(status={status}) message: "{message}"'.format(name=item.link.name,
671- status=status_code,
672- message=message))
673- if status in STATUS_ICONS:
674- if item.status == status:
675- return
676- item.status = status
677- item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
678- if status in ERROR_STRING:
679- status_code = ERROR_STRING[status]
680- elif status in STATUS_STRING:
681- status_code = STATUS_STRING[status]
682- log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=status_code))
683- item.widget.setIcon(item.icon)
684- self.update_icons()
685+ if item is None:
686+ log.error('ProjectorManager: Unknown item "{ip}" - not updating status'.format(ip=ip))
687+ return
688+ elif item.status == status:
689+ log.debug('ProjectorManager: No status change for "{ip}" - not updating status'.format(ip=ip))
690+ return
691+
692+ item.status = status
693+ item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
694+ log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=STATUS_CODE[status]))
695+ item.widget.setIcon(item.icon)
696+ return self.update_icons()
697
698 def get_toolbar_item(self, name, enabled=False, hidden=False):
699 item = self.one_toolbar.findChild(QtWidgets.QAction, name)
700@@ -877,7 +881,7 @@
701 self.get_toolbar_item('show_projector_multiple', hidden=True)
702 elif count == 1:
703 projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)
704- connected = projector.link.state() == projector.link.ConnectedState
705+ connected = QSOCKET_STATE[projector.link.state()] == S_CONNECTED
706 power = projector.link.power == S_ON
707 self.get_toolbar_item('connect_projector_multiple', hidden=True)
708 self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
709
710=== modified file 'openlp/core/projectors/pjlink.py'
711--- openlp/core/projectors/pjlink.py 2017-12-29 09:15:48 +0000
712+++ openlp/core/projectors/pjlink.py 2018-01-03 05:54:24 +0000
713@@ -54,11 +54,12 @@
714
715 from openlp.core.common import qmd5_hash
716 from openlp.core.common.i18n import translate
717-from openlp.core.projectors.constants import CONNECTION_ERRORS, CR, ERROR_MSG, ERROR_STRING, \
718- E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, E_OK, \
719- E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, PJLINK_ERST_DATA, \
720- PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_POWR_STATUS, PJLINK_VALID_CMD, \
721- STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_QSOCKET_STATE, S_STATUS
722+from openlp.core.projectors.constants import CONNECTION_ERRORS, PJLINK_CLASS, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \
723+ PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PREFIX, PJLINK_PORT, PJLINK_POWR_STATUS, \
724+ PJLINK_SUFFIX, PJLINK_VALID_CMD, PROJECTOR_STATE, STATUS_CODE, STATUS_MSG, QSOCKET_STATE, \
725+ E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, \
726+ E_OK, E_SOCKET_TIMEOUT, \
727+ S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS
728
729 log = logging.getLogger(__name__)
730 log.debug('pjlink loaded')
731@@ -69,12 +70,9 @@
732 SocketError = QtNetwork.QAbstractSocket.SocketError
733 SocketSTate = QtNetwork.QAbstractSocket.SocketState
734
735-PJLINK_PREFIX = '%'
736-PJLINK_CLASS = '1' # Default to class 1 until we query the projector
737 # Add prefix here, but defer linkclass expansion until later when we have the actual
738 # PJLink class for the command
739 PJLINK_HEADER = '{prefix}{{linkclass}}'.format(prefix=PJLINK_PREFIX)
740-PJLINK_SUFFIX = CR
741
742
743 class PJLinkUDP(QtNetwork.QUdpSocket):
744@@ -136,8 +134,9 @@
745 """
746 Initialize instance variables. Also used to reset projector-specific information to default.
747 """
748+ conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
749 log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip,
750- state=S_QSOCKET_STATE[self.state()]))
751+ state=conn_state))
752 self.fan = None # ERST
753 self.filter_time = None # FILT
754 self.lamp = None # LAMP
755@@ -183,42 +182,25 @@
756 # Due to some replies should stay as mixed-case, validate using separate uppercase check
757 _data = data.upper()
758 # Check if we have a future command not available yet
759- if cmd not in PJLINK_VALID_CMD:
760- log.error('({ip}) Ignoring command="{cmd}" (Invalid/Unknown)'.format(ip=self.ip, cmd=cmd))
761+ if cmd not in self.pjlink_functions:
762+ log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd))
763 return
764 elif _data == 'OK':
765 log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=self.ip, cmd=cmd))
766 # A command returned successfully, so do a query on command to verify status
767 return self.send_command(cmd=cmd)
768- elif cmd not in self.pjlink_functions:
769- log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd))
770- return
771 elif _data in PJLINK_ERRORS:
772 # Oops - projector error
773- log.error('({ip}) Projector returned error "{data}"'.format(ip=self.ip, data=data))
774- if _data == PJLINK_ERRORS[E_AUTHENTICATION]:
775- # Authentication error
776+ log.error('({ip}) {cmd}: {err}'.format(ip=self.ip,
777+ cmd=cmd,
778+ err=STATUS_MSG[PJLINK_ERRORS[_data]]))
779+ if PJLINK_ERRORS[_data] == E_AUTHENTICATION:
780 self.disconnect_from_host()
781- self.change_status(E_AUTHENTICATION)
782- log.debug('({ip}) emitting projectorAuthentication() signal'.format(ip=self.ip))
783 self.projectorAuthentication.emit(self.name)
784- elif _data == PJLINK_ERRORS[E_UNDEFINED]:
785- # Projector does not recognize command
786- self.change_status(E_UNDEFINED, '{error}: "{data}"'.format(error=ERROR_MSG[E_UNDEFINED],
787- data=cmd))
788- elif _data == PJLINK_ERRORS[E_PARAMETER]:
789- # Invalid parameter
790- self.change_status(E_PARAMETER)
791- elif _data == PJLINK_ERRORS[E_UNAVAILABLE]:
792- # Projector busy
793- self.change_status(E_UNAVAILABLE)
794- elif _data == PJLINK_ERRORS[E_PROJECTOR]:
795- # Projector/display error
796- self.change_status(E_PROJECTOR)
797- return
798+ return self.change_status(status=E_AUTHENTICATION)
799 # Command checks already passed
800 log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd))
801- self.pjlink_functions[cmd](data)
802+ self.pjlink_functions[cmd](data=data)
803
804 def process_avmt(self, data):
805 """
806@@ -313,22 +295,22 @@
807 data[PJLINK_ERST_DATA['COVER']],
808 data[PJLINK_ERST_DATA['FILTER']],
809 data[PJLINK_ERST_DATA['OTHER']])
810- if fan != PJLINK_ERST_STATUS[E_OK]:
811+ if fan != PJLINK_ERST_STATUS[S_OK]:
812 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Fan')] = \
813 PJLINK_ERST_STATUS[fan]
814- if lamp != PJLINK_ERST_STATUS[E_OK]:
815+ if lamp != PJLINK_ERST_STATUS[S_OK]:
816 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Lamp')] = \
817 PJLINK_ERST_STATUS[lamp]
818- if temp != PJLINK_ERST_STATUS[E_OK]:
819+ if temp != PJLINK_ERST_STATUS[S_OK]:
820 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Temperature')] = \
821 PJLINK_ERST_STATUS[temp]
822- if cover != PJLINK_ERST_STATUS[E_OK]:
823+ if cover != PJLINK_ERST_STATUS[S_OK]:
824 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Cover')] = \
825 PJLINK_ERST_STATUS[cover]
826- if filt != PJLINK_ERST_STATUS[E_OK]:
827+ if filt != PJLINK_ERST_STATUS[S_OK]:
828 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Filter')] = \
829 PJLINK_ERST_STATUS[filt]
830- if other != PJLINK_ERST_STATUS[E_OK]:
831+ if other != PJLINK_ERST_STATUS[S_OK]:
832 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Other')] = \
833 PJLINK_ERST_STATUS[other]
834 return
835@@ -373,8 +355,18 @@
836
837 :param data: Currently selected source
838 """
839+ # First, see if we have a valid input based on what is installed (if available)
840+ if self.source_available is not None:
841+ # We have available inputs, so verify it's in the list
842+ if data not in self.source_available:
843+ log.warn('({ip}) Input source not listed in available sources - ignoring'.format(ip=self.ip))
844+ return
845+ elif data not in PJLINK_DEFAULT_CODES:
846+ # Hmm - no sources available yet, so check with PJLink defaults
847+ log.warn('({ip}) Input source not listed as a PJLink available source - ignoring'.format(ip=self.ip))
848+ return
849 self.source = data
850- log.info('({ip}) Setting data source to "{data}"'.format(ip=self.ip, data=self.source))
851+ log.debug('({ip}) Setting data source to "{data}"'.format(ip=self.ip, data=self.source))
852 return
853
854 def process_inst(self, data):
855@@ -390,7 +382,6 @@
856 sources.append(source)
857 sources.sort()
858 self.source_available = sources
859- self.projectorUpdateIcons.emit()
860 log.debug('({ip}) Setting projector sources_available to "{data}"'.format(ip=self.ip,
861 data=self.source_available))
862 return
863@@ -551,17 +542,15 @@
864 return
865 elif self.sw_version is None:
866 log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=self.ip, data=data))
867- self.sw_version = data
868- self.db_update = True
869 else:
870- # Compare software version and see if we got the same projector
871- if self.serial_no != data:
872+ if self.sw_version != data:
873 log.warning('({ip}) Projector software version does not match saved '
874 'software version'.format(ip=self.ip))
875 log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.sw_version))
876 log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data))
877- log.warning('({ip}) Saving new serial number as sw_version_received'.format(ip=self.ip))
878- self.sw_version_received = data
879+ log.warning('({ip}) Updating software version'.format(ip=self.ip))
880+ self.sw_version = data
881+ self.db_update = True
882
883
884 class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
885@@ -678,7 +667,7 @@
886 Retrieve information from projector that changes.
887 Normally called by timer().
888 """
889- if self.state() != S_QSOCKET_STATE['ConnectedState']:
890+ if QSOCKET_STATE[self.state()] != S_CONNECTED:
891 log.warning('({ip}) poll_loop(): Not connected - returning'.format(ip=self.ip))
892 return
893 log.debug('({ip}) poll_loop(): Updating projector status'.format(ip=self.ip))
894@@ -688,13 +677,8 @@
895 self.timer.setInterval(self.poll_time)
896 # Restart timer
897 self.timer.start()
898- # These commands may change during connection
899- check_list = ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']
900- if self.pjlink_class == '2':
901- check_list.extend(['FILT', 'FREZ'])
902- for command in check_list:
903- self.send_command(command)
904 # The following commands do not change, so only check them once
905+ # Call them first in case other functions rely on something here
906 if self.power == S_ON and self.source_available is None:
907 self.send_command('INST')
908 if self.other_info is None:
909@@ -715,22 +699,28 @@
910 self.send_command('RFIL')
911 if self.model_lamp is None:
912 self.send_command('RLMP')
913+ # These commands may change during connection
914+ check_list = ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']
915+ if self.pjlink_class == '2':
916+ check_list.extend(['FILT', 'FREZ'])
917+ for command in check_list:
918+ self.send_command(command)
919
920 def _get_status(self, status):
921 """
922 Helper to retrieve status/error codes and convert to strings.
923
924 :param status: Status/Error code
925- :returns: (Status/Error code, String)
926+ :returns: tuple (-1 if code not INT, None)
927+ :returns: tuple (string: code as string, None if no description)
928+ :returns: tuple (string: code as string, string: Status/Error description)
929 """
930 if not isinstance(status, int):
931- return -1, 'Invalid status code'
932- elif status in ERROR_STRING:
933- return ERROR_STRING[status], ERROR_MSG[status]
934- elif status in STATUS_STRING:
935- return STATUS_STRING[status], ERROR_MSG[status]
936+ return -1, None
937+ elif status not in STATUS_MSG:
938+ return None, None
939 else:
940- return status, translate('OpenLP.PJLink', 'Unknown status')
941+ return STATUS_CODE[status], STATUS_MSG[status]
942
943 def change_status(self, status, msg=None):
944 """
945@@ -740,19 +730,27 @@
946 :param status: Status code
947 :param msg: Optional message
948 """
949- message = translate('OpenLP.PJLink', 'No message') if msg is None else msg
950- (code, message) = self._get_status(status)
951- if msg is not None:
952- message = msg
953+ if status in STATUS_CODE:
954+ log.debug('({ip}) Changing status to {status} '
955+ '"{msg}"'.format(ip=self.ip,
956+ status=STATUS_CODE[status],
957+ msg=msg if msg is not None else STATUS_MSG[status]))
958+ else:
959+ log.warning('({ip}) Unknown status change code: {code}'.format(ip=self.ip,
960+ code=status))
961+ return
962 if status in CONNECTION_ERRORS:
963- # Projector, connection state
964- self.projector_status = self.error_status = self.status_connect = E_NOT_CONNECTED
965- elif status >= S_NOT_CONNECTED and status < S_STATUS:
966+ # Connection state error affects both socket and projector
967+ self.error_status = status
968+ self.status_connect = E_NOT_CONNECTED
969+ elif status >= S_NOT_CONNECTED and status in QSOCKET_STATE:
970+ # Socket connection status update
971 self.status_connect = status
972- self.projector_status = S_NOT_CONNECTED
973- elif status <= S_INFO:
974- self.status_connect = S_CONNECTED
975+ elif status >= S_NOT_CONNECTED and status in PROJECTOR_STATE:
976+ # Only affects the projector status
977 self.projector_status = status
978+
979+ # These log entries are for troubleshooting only
980 (status_code, status_message) = self._get_status(self.status_connect)
981 log.debug('({ip}) status_connect: {code}: "{message}"'.format(ip=self.ip,
982 code=status_code,
983@@ -765,6 +763,15 @@
984 log.debug('({ip}) error_status: {code}: "{message}"'.format(ip=self.ip,
985 code=status_code,
986 message=status_message if msg is None else msg))
987+
988+ # Now that we logged extra information for debugging, broadcast the original change/message
989+ (code, message) = self._get_status(status)
990+ if msg is not None:
991+ message = msg
992+ elif message is None:
993+ # No message for status code
994+ message = translate('OpenLP.PJLink', 'No message') if msg is None else msg
995+
996 self.changeStatus.emit(self.ip, status, message)
997 self.projectorUpdateIcons.emit()
998
999@@ -794,7 +801,7 @@
1000 data = decode(read, 'utf-8')
1001 # Possibility of extraneous data on input when reading.
1002 # Clean out extraneous characters in buffer.
1003- self.readLine(self.max_size)
1004+ self.read(1024)
1005 log.debug('({ip}) check_login() read "{data}"'.format(ip=self.ip, data=data.strip()))
1006 # At this point, we should only have the initial login prompt with
1007 # possible authentication
1008@@ -805,6 +812,7 @@
1009 # Invalid initial packet - close socket
1010 log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.ip))
1011 return self.disconnect_from_host()
1012+ # Convert the initial login prompt with the expected PJLink normal command format for processing
1013 log.debug('({ip}) check_login(): Formatting initial connection prompt to PJLink packet'.format(ip=self.ip))
1014 return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX,
1015 clss='1',
1016@@ -895,7 +903,7 @@
1017 Get data from TCP socket.
1018 """
1019 log.debug('({ip}) get_socket(): Reading data'.format(ip=self.ip))
1020- if self.state() != self.ConnectedState:
1021+ if QSOCKET_STATE[self.state()] != S_CONNECTED:
1022 log.debug('({ip}) get_socket(): Not connected - returning'.format(ip=self.ip))
1023 self.send_busy = False
1024 return
1025@@ -907,8 +915,7 @@
1026 log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.ip))
1027 return self.receive_data_signal()
1028 self.socket_timer.stop()
1029- self.get_data(buff=read, ip=self.ip)
1030- return self.receive_data_signal()
1031+ return self.get_data(buff=read, ip=self.ip)
1032
1033 def get_data(self, buff, ip=None):
1034 """
1035@@ -927,13 +934,17 @@
1036 data = data_in.strip()
1037 # Initial packet checks
1038 if (len(data) < 7):
1039- return self._trash_buffer(msg='get_data(): Invalid packet - length')
1040+ self._trash_buffer(msg='get_data(): Invalid packet - length')
1041+ return self.receive_data_signal()
1042 elif len(data) > self.max_size:
1043- return self._trash_buffer(msg='get_data(): Invalid packet - too long')
1044+ self._trash_buffer(msg='get_data(): Invalid packet - too long')
1045+ return self.receive_data_signal()
1046 elif not data.startswith(PJLINK_PREFIX):
1047- return self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')
1048+ self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')
1049+ return self.receive_data_signal()
1050 elif '=' not in data:
1051- return self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')
1052+ self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')
1053+ return self.receive_data_signal()
1054 log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))
1055 header, data = data.split('=')
1056 # At this point, the header should contain:
1057@@ -947,15 +958,17 @@
1058 except ValueError as e:
1059 self.change_status(E_INVALID_DATA)
1060 log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in))
1061- return self._trash_buffer('get_data(): Expected header + command + data')
1062+ self._trash_buffer('get_data(): Expected header + command + data')
1063+ return self.receive_data_signal()
1064 if cmd not in PJLINK_VALID_CMD:
1065 log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
1066- return self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
1067+ self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
1068+ return self.receive_data_signal()
1069 if int(self.pjlink_class) < int(version):
1070 log.warning('({ip}) get_data(): Projector returned class reply higher '
1071 'than projector stated class'.format(ip=self.ip))
1072- self.send_busy = False
1073- return self.process_command(cmd, data)
1074+ self.process_command(cmd, data)
1075+ return self.receive_data_signal()
1076
1077 @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
1078 def get_error(self, err):
1079@@ -993,7 +1006,7 @@
1080 :param salt: Optional salt for md5 hash initial authentication
1081 :param priority: Option to send packet now rather than queue it up
1082 """
1083- if self.state() != self.ConnectedState:
1084+ if QSOCKET_STATE[self.state()] != S_CONNECTED:
1085 log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
1086 return self.reset_information()
1087 if cmd not in PJLINK_VALID_CMD:
1088@@ -1018,7 +1031,7 @@
1089 header=header,
1090 command=cmd,
1091 options=opts,
1092- suffix=CR)
1093+ suffix=PJLINK_SUFFIX)
1094 if out in self.priority_queue:
1095 log.debug('({ip}) send_command(): Already in priority queue - skipping'.format(ip=self.ip))
1096 elif out in self.send_queue:
1097@@ -1044,9 +1057,10 @@
1098 """
1099 # Funny looking data check, but it's a quick check for data=None
1100 log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.ip, data=data.strip() if data else data))
1101+ conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
1102 log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.ip,
1103- data=S_QSOCKET_STATE[self.state()]))
1104- if self.state() != self.ConnectedState:
1105+ data=conn_state))
1106+ if QSOCKET_STATE[self.state()] != S_CONNECTED:
1107 log.debug('({ip}) _send_command() Not connected - abort'.format(ip=self.ip))
1108 self.send_busy = False
1109 return self.disconnect_from_host()
1110@@ -1088,10 +1102,11 @@
1111 """
1112 Initiate connection to projector.
1113 """
1114- log.debug('{ip}) connect_to_host(): Starting connection'.format(ip=self.ip))
1115- if self.state() == self.ConnectedState:
1116+ log.debug('({ip}) connect_to_host(): Starting connection'.format(ip=self.ip))
1117+ if QSOCKET_STATE[self.state()] == S_CONNECTED:
1118 log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
1119 return
1120+ self.error_status = S_OK
1121 self.change_status(S_CONNECTING)
1122 self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port))
1123
1124@@ -1100,12 +1115,13 @@
1125 """
1126 Close socket and cleanup.
1127 """
1128- if abort or self.state() != self.ConnectedState:
1129+ if abort or QSOCKET_STATE[self.state()] != S_NOT_CONNECTED:
1130 if abort:
1131 log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
1132+ self.abort()
1133 else:
1134 log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.ip))
1135- self.disconnectFromHost()
1136+ self.disconnectFromHost()
1137 try:
1138 self.readyRead.disconnect(self.get_socket)
1139 except TypeError:
1140@@ -1201,7 +1217,7 @@
1141 elif src not in self.source_available:
1142 return
1143 log.debug('({ip}) Setting input source to "{data}"'.format(ip=self.ip, data=src))
1144- self.send_command(cmd='INPT', opts=src)
1145+ self.send_command(cmd='INPT', opts=src, priority=True)
1146 self.poll_loop()
1147
1148 def set_power_on(self):
1149@@ -1209,7 +1225,7 @@
1150 Send command to turn power to on.
1151 """
1152 log.debug('({ip}) Setting POWR to 1 (on)'.format(ip=self.ip))
1153- self.send_command(cmd='POWR', opts='1')
1154+ self.send_command(cmd='POWR', opts='1', priority=True)
1155 self.poll_loop()
1156
1157 def set_power_off(self):
1158@@ -1217,7 +1233,7 @@
1159 Send command to turn power to standby.
1160 """
1161 log.debug('({ip}) Setting POWR to 0 (standby)'.format(ip=self.ip))
1162- self.send_command(cmd='POWR', opts='0')
1163+ self.send_command(cmd='POWR', opts='0', priority=True)
1164 self.poll_loop()
1165
1166 def set_shutter_closed(self):
1167@@ -1225,7 +1241,7 @@
1168 Send command to set shutter to closed position.
1169 """
1170 log.debug('({ip}) Setting AVMT to 11 (shutter closed)'.format(ip=self.ip))
1171- self.send_command(cmd='AVMT', opts='11')
1172+ self.send_command(cmd='AVMT', opts='11', priority=True)
1173 self.poll_loop()
1174
1175 def set_shutter_open(self):
1176@@ -1233,8 +1249,9 @@
1177 Send command to set shutter to open position.
1178 """
1179 log.debug('({ip}) Setting AVMT to "10" (shutter open)'.format(ip=self.ip))
1180- self.send_command(cmd='AVMT', opts='10')
1181+ self.send_command(cmd='AVMT', opts='10', priority=True)
1182 self.poll_loop()
1183+ self.projectorUpdateIcons.emit()
1184
1185 def receive_data_signal(self):
1186 """
1187
1188=== modified file 'tests/functional/openlp_core/projectors/test_projector_constants.py'
1189--- tests/functional/openlp_core/projectors/test_projector_constants.py 2017-11-10 11:59:38 +0000
1190+++ tests/functional/openlp_core/projectors/test_projector_constants.py 2018-01-03 05:54:24 +0000
1191@@ -23,12 +23,51 @@
1192 Package to test the openlp.core.projectors.constants module.
1193 """
1194 from unittest import TestCase
1195+from openlp.core.projectors import constants
1196+from openlp.core.projectors.constants import STATUS_CODE, STATUS_MSG
1197
1198
1199 class TestProjectorConstants(TestCase):
1200 """
1201 Test specific functions in the projector constants module.
1202 """
1203+ def test_defined_codes_in_status_code(self):
1204+ """
1205+ Test defined status/error codes have equivalent strings
1206+ """
1207+ check = []
1208+ missing_str = []
1209+
1210+ # GIVEN: List of defined E_* and S_* items defined in constants
1211+ for item in constants.__dict__:
1212+ if item.startswith('E_') or item.startswith('S_'):
1213+ check.append(item)
1214+
1215+ # WHEN: Verify defined list against STATUS_STR
1216+ for item in check:
1217+ if constants.__dict__[item] not in STATUS_CODE:
1218+ missing_str.append(item)
1219+
1220+ # THEN: There should be no missing items
1221+ assert 0 == len(missing_str), 'Status string missing: {msg}'.format(msg=missing_str)
1222+
1223+ def test_status_code_in_status_message(self):
1224+ """
1225+ Test if entries in STATUS_CODE have equivalent descriptions in STATUS_MSG
1226+ """
1227+ missing_msg = []
1228+
1229+ # GIVEN: Test items
1230+ check = STATUS_CODE
1231+
1232+ # WHEN: Verify each entry in STATUS_MSG against STATUS_CODE
1233+ for item in check:
1234+ if item not in STATUS_MSG:
1235+ missing_msg.append(item)
1236+
1237+ # THEN: There should be no missing items
1238+ assert 0 == len(missing_msg), 'Status message missing: {msg}'.format(msg=missing_msg)
1239+
1240 def test_build_pjlink_video_label(self):
1241 """
1242 Test building PJLINK_DEFAULT_CODES dictionary
1243
1244=== modified file 'tests/functional/openlp_core/projectors/test_projector_pjlink_base.py'
1245--- tests/functional/openlp_core/projectors/test_projector_pjlink_base.py 2017-12-28 08:22:55 +0000
1246+++ tests/functional/openlp_core/projectors/test_projector_pjlink_base.py 2018-01-03 05:54:24 +0000
1247@@ -25,7 +25,7 @@
1248 from unittest import TestCase
1249 from unittest.mock import call, patch, MagicMock
1250
1251-from openlp.core.projectors.constants import E_PARAMETER, ERROR_STRING, S_ON, S_CONNECTED, S_QSOCKET_STATE
1252+from openlp.core.projectors.constants import E_PARAMETER, STATUS_CODE, S_ON, S_CONNECTED, QSOCKET_STATE
1253 from openlp.core.projectors.db import Projector
1254 from openlp.core.projectors.pjlink import PJLink
1255 from tests.resources.projector.data import TEST1_DATA
1256@@ -64,7 +64,7 @@
1257 # as first parameter
1258 mock_change_status.called_with(E_PARAMETER,
1259 'change_status should have been called with "{}"'.format(
1260- ERROR_STRING[E_PARAMETER]))
1261+ STATUS_CODE[E_PARAMETER]))
1262
1263 @patch.object(pjlink_test, 'disconnect_from_host')
1264 def test_socket_abort(self, mock_disconnect):
1265@@ -103,7 +103,7 @@
1266 """
1267 # GIVEN: Mocks and test data
1268 mock_state = patch.object(self.pjlink_test, 'state').start()
1269- mock_state.return_value = S_QSOCKET_STATE['ConnectedState']
1270+ mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
1271 mock_timer = patch.object(self.pjlink_test, 'timer').start()
1272 mock_timer.interval.return_value = 10
1273 mock_send_command = patch.object(self.pjlink_test, 'send_command').start()
1274@@ -116,7 +116,6 @@
1275 pjlink.manufacturer = None
1276 pjlink.model = None
1277 pjlink.pjlink_name = None
1278- pjlink.ConnectedState = S_CONNECTED
1279 call_list = [
1280 call('POWR'),
1281 call('ERST'),
1282
1283=== modified file 'tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py'
1284--- tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2017-12-09 11:17:05 +0000
1285+++ tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2018-01-03 05:54:24 +0000
1286@@ -24,209 +24,222 @@
1287 """
1288
1289 from unittest import TestCase
1290-from unittest.mock import patch, MagicMock
1291+from unittest.mock import MagicMock, call, patch
1292
1293 import openlp.core.projectors.pjlink
1294-from openlp.core.projectors.constants import PJLINK_ERRORS, \
1295+from openlp.core.projectors.constants import PJLINK_ERRORS, PJLINK_PREFIX, STATUS_MSG, \
1296 E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED
1297 from openlp.core.projectors.db import Projector
1298 from openlp.core.projectors.pjlink import PJLink
1299
1300-'''
1301-from openlp.core.projectors.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \
1302- PJLINK_POWR_STATUS, PJLINK_VALID_CMD, E_WARN, E_ERROR, S_OFF, S_STANDBY, S_ON
1303-'''
1304-from tests.resources.projector.data import TEST_PIN, TEST1_DATA
1305-
1306-pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
1307-pjlink_test.ip = '127.0.0.1'
1308+from tests.resources.projector.data import TEST1_DATA
1309
1310
1311 class TestPJLinkRouting(TestCase):
1312 """
1313 Tests for the PJLink module command routing
1314 """
1315- def setUp(self):
1316- '''
1317- TestPJLinkCommands part 2 initialization
1318- '''
1319- self.pjlink_test = PJLink(Projector(**TEST1_DATA), no_poll=True)
1320-
1321- def tearDown(self):
1322- '''
1323- TestPJLinkCommands part 2 cleanups
1324- '''
1325- self.pjlink_test = None
1326-
1327- @patch.object(openlp.core.projectors.pjlink, 'log')
1328- def test_process_command_call_clss(self, mock_log):
1329+ def test_get_data_unknown_command(self):
1330+ """
1331+ Test not a valid command
1332+ """
1333+ # GIVEN: Test object
1334+ log_warning_text = [call('(111.111.111.111) get_data(): Invalid packet - unknown command "UNK"')]
1335+ log_debug_text = [call('(111.111.111.111) get_data(ip="111.111.111.111" buffer="b\'%1UNK=Huh?\'"'),
1336+ call('(111.111.111.111) get_data(): Checking new data "%1UNK=Huh?"')]
1337+
1338+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1339+ patch.object(openlp.core.projectors.pjlink.PJLink, '_trash_buffer') as mock_buffer:
1340+
1341+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1342+ pjlink.pjlink_functions = MagicMock()
1343+
1344+ # WHEN: get_data called with an unknown command
1345+ pjlink.get_data(buff='{prefix}1UNK=Huh?'.format(prefix=PJLINK_PREFIX).encode('utf-8'))
1346+
1347+ # THEN: Appropriate log entries should have been made and methods called/not called
1348+ mock_log.debug.assert_has_calls(log_debug_text)
1349+ mock_log.warning.assert_has_calls(log_warning_text)
1350+ assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions'
1351+ assert mock_buffer.called is True, 'Should have called _trash_buffer'
1352+
1353+ def test_process_command_call_clss(self):
1354 """
1355 Test process_command calls proper function
1356 """
1357+ # GIVEN: Test object and mocks
1358+ log_debug_calls = [call('(111.111.111.111) Processing command "CLSS" with data "1"'),
1359+ call('(111.111.111.111) Calling function for CLSS')]
1360+
1361+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1362+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1363+
1364+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1365+
1366+ # WHEN: process_command is called with valid function and data
1367+ pjlink.process_command(cmd='CLSS', data='1')
1368+
1369+ # THEN: Appropriate log entries should have been made and methods called
1370+ mock_log.debug.assert_has_calls(log_debug_calls)
1371+ mock_process_clss.assert_called_once_with(data='1')
1372+
1373+ def test_process_command_erra(self):
1374+ """
1375+ Test ERRA - Authentication Error
1376+ """
1377 # GIVEN: Test object
1378- pjlink = pjlink_test
1379- log_text = '(127.0.0.1) Calling function for CLSS'
1380- mock_log.reset_mock()
1381- mock_process_clss = MagicMock()
1382- pjlink.pjlink_functions['CLSS'] = mock_process_clss
1383-
1384- # WHEN: process_command is called with valid function and data
1385- pjlink.process_command(cmd='CLSS', data='1')
1386-
1387- # THEN: Process method should have been called properly
1388- mock_log.debug.assert_called_with(log_text)
1389- mock_process_clss.assert_called_with('1')
1390-
1391- @patch.object(pjlink_test, 'change_status')
1392- @patch.object(openlp.core.projectors.pjlink, 'log')
1393- def test_process_command_err1(self, mock_log, mock_change_status):
1394+ log_error_calls = [call('(111.111.111.111) PJLINK: {msg}'.format(msg=STATUS_MSG[E_AUTHENTICATION]))]
1395+ log_debug_calls = [call('(111.111.111.111) Processing command "PJLINK" with data "ERRA"')]
1396+
1397+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1398+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_pjlink') as mock_process_pjlink, \
1399+ patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
1400+ patch.object(openlp.core.projectors.pjlink.PJLink, 'disconnect_from_host') as mock_disconnect, \
1401+ patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorAuthentication') as mock_authentication:
1402+
1403+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1404+
1405+ # WHEN: process_command called with ERRA
1406+ pjlink.process_command(cmd='PJLINK', data=PJLINK_ERRORS[E_AUTHENTICATION])
1407+
1408+ # THEN: Appropriate log entries should have been made and methods called/not called
1409+ assert mock_disconnect.called is True, 'disconnect_from_host should have been called'
1410+ mock_log.error.assert_has_calls(log_error_calls)
1411+ mock_log.debug.assert_has_calls(log_debug_calls)
1412+ mock_change_status.assert_called_once_with(status=E_AUTHENTICATION)
1413+ mock_authentication.emit.assert_called_once_with(pjlink.name)
1414+ mock_process_pjlink.assert_not_called()
1415+
1416+ def test_process_command_err1(self):
1417 """
1418 Test ERR1 - Undefined projector function
1419 """
1420 # GIVEN: Test object
1421- pjlink = pjlink_test
1422- log_text = '(127.0.0.1) Projector returned error "ERR1"'
1423- mock_change_status.reset_mock()
1424- mock_log.reset_mock()
1425-
1426- # WHEN: process_command called with ERR1
1427- pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
1428-
1429- # THEN: Error should be logged and status_change should be called
1430- mock_change_status.assert_called_once_with(E_UNDEFINED, 'Undefined Command: "CLSS"')
1431- mock_log.error.assert_called_with(log_text)
1432-
1433- @patch.object(pjlink_test, 'change_status')
1434- @patch.object(openlp.core.projectors.pjlink, 'log')
1435- def test_process_command_err2(self, mock_log, mock_change_status):
1436+ log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_UNDEFINED]))]
1437+ log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR1"'),
1438+ call('(111.111.111.111) Calling function for CLSS')]
1439+
1440+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1441+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1442+
1443+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1444+
1445+ # WHEN: process_command called with ERR1
1446+ pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
1447+
1448+ # THEN: Appropriate log entries should have been made and methods called
1449+ mock_log.error.assert_has_calls(log_error_text)
1450+ mock_log.debug.assert_has_calls(log_debug_text)
1451+ mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNDEFINED])
1452+
1453+ def test_process_command_err2(self):
1454 """
1455 Test ERR2 - Parameter Error
1456 """
1457 # GIVEN: Test object
1458- pjlink = pjlink_test
1459- log_text = '(127.0.0.1) Projector returned error "ERR2"'
1460- mock_change_status.reset_mock()
1461- mock_log.reset_mock()
1462-
1463- # WHEN: process_command called with ERR2
1464- pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
1465-
1466- # THEN: Error should be logged and status_change should be called
1467- mock_change_status.assert_called_once_with(E_PARAMETER)
1468- mock_log.error.assert_called_with(log_text)
1469-
1470- @patch.object(pjlink_test, 'change_status')
1471- @patch.object(openlp.core.projectors.pjlink, 'log')
1472- def test_process_command_err3(self, mock_log, mock_change_status):
1473- """
1474- Test ERR3 - Unavailable error
1475- """
1476- # GIVEN: Test object
1477- pjlink = pjlink_test
1478- log_text = '(127.0.0.1) Projector returned error "ERR3"'
1479- mock_change_status.reset_mock()
1480- mock_log.reset_mock()
1481-
1482- # WHEN: process_command called with ERR3
1483- pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
1484-
1485- # THEN: Error should be logged and status_change should be called
1486- mock_change_status.assert_called_once_with(E_UNAVAILABLE)
1487- mock_log.error.assert_called_with(log_text)
1488-
1489- @patch.object(pjlink_test, 'change_status')
1490- @patch.object(openlp.core.projectors.pjlink, 'log')
1491- def test_process_command_err4(self, mock_log, mock_change_status):
1492- """
1493- Test ERR3 - Unavailable error
1494- """
1495- # GIVEN: Test object
1496- pjlink = pjlink_test
1497- log_text = '(127.0.0.1) Projector returned error "ERR4"'
1498- mock_change_status.reset_mock()
1499- mock_log.reset_mock()
1500-
1501- # WHEN: process_command called with ERR3
1502- pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
1503-
1504- # THEN: Error should be logged and status_change should be called
1505- mock_change_status.assert_called_once_with(E_PROJECTOR)
1506- mock_log.error.assert_called_with(log_text)
1507-
1508- @patch.object(pjlink_test, 'projectorAuthentication')
1509- @patch.object(pjlink_test, 'change_status')
1510- @patch.object(pjlink_test, 'disconnect_from_host')
1511- @patch.object(openlp.core.projectors.pjlink, 'log')
1512- def test_process_command_erra(self, mock_log, mock_disconnect, mock_change_status, mock_err_authenticate):
1513- """
1514- Test ERRA - Authentication Error
1515- """
1516- # GIVEN: Test object
1517- pjlink = pjlink_test
1518- log_text = '(127.0.0.1) Projector returned error "ERRA"'
1519- mock_change_status.reset_mock()
1520- mock_log.reset_mock()
1521-
1522- # WHEN: process_command called with ERRA
1523- pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_AUTHENTICATION])
1524-
1525- # THEN: Error should be logged and several methods should be called
1526- self.assertTrue(mock_disconnect.called, 'disconnect_from_host should have been called')
1527- mock_change_status.assert_called_once_with(E_AUTHENTICATION)
1528- mock_log.error.assert_called_with(log_text)
1529+ log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_PARAMETER]))]
1530+ log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR2"'),
1531+ call('(111.111.111.111) Calling function for CLSS')]
1532+
1533+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1534+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1535+
1536+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1537+
1538+ # WHEN: process_command called with ERR2
1539+ pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
1540+
1541+ # THEN: Appropriate log entries should have been made and methods called/not called
1542+ mock_log.error.assert_has_calls(log_error_text)
1543+ mock_log.debug.assert_has_calls(log_debug_text)
1544+ mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PARAMETER])
1545+
1546+ def test_process_command_err3(self):
1547+ """
1548+ Test ERR3 - Unavailable error
1549+ """
1550+ # GIVEN: Test object
1551+ log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_UNAVAILABLE]))]
1552+ log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR3"'),
1553+ call('(111.111.111.111) Calling function for CLSS')]
1554+
1555+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1556+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1557+
1558+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1559+
1560+ # WHEN: process_command called with ERR3
1561+ pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
1562+
1563+ # THEN: Appropriate log entries should have been made and methods called
1564+ mock_log.error.assert_has_calls(log_error_text)
1565+ mock_log.debug.assert_has_calls(log_debug_text)
1566+ mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNAVAILABLE])
1567+
1568+ def test_process_command_err4(self):
1569+ """
1570+ Test ERR3 - Unavailable error
1571+ """
1572+ # GIVEN: Test object
1573+ log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_PROJECTOR]))]
1574+ log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR4"'),
1575+ call('(111.111.111.111) Calling function for CLSS')]
1576+
1577+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1578+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1579+
1580+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1581+
1582+ # WHEN: process_command called with ERR4
1583+ pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
1584+
1585+ # THEN: Appropriate log entries should have been made and methods called
1586+ mock_log.error.assert_has_calls(log_error_text)
1587+ mock_log.debug.assert_has_calls(log_debug_text)
1588+ mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PROJECTOR])
1589
1590 def test_process_command_future(self):
1591 """
1592 Test command valid but no method to process yet
1593 """
1594- # GIVEN: Initial mocks and data
1595- mock_log = patch.object(openlp.core.projectors.pjlink, 'log').start()
1596- mock_functions = patch.object(self.pjlink_test, 'pjlink_functions').start()
1597- mock_functions.return_value = []
1598-
1599- pjlink = self.pjlink_test
1600- log_text = '(111.111.111.111) Unable to process command="CLSS" (Future option?)'
1601-
1602- # WHEN: process_command called with an unknown command
1603- pjlink.process_command(cmd='CLSS', data='DONT CARE')
1604-
1605- # THEN: Error should be logged and no command called
1606- self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')
1607- mock_log.warning.assert_called_once_with(log_text)
1608-
1609- @patch.object(pjlink_test, 'pjlink_functions')
1610- @patch.object(openlp.core.projectors.pjlink, 'log')
1611- def test_process_command_invalid(self, mock_log, mock_functions):
1612- """
1613- Test not a valid command
1614- """
1615 # GIVEN: Test object
1616- pjlink = pjlink_test
1617- mock_functions.reset_mock()
1618- mock_log.reset_mock()
1619-
1620- # WHEN: process_command called with an unknown command
1621- pjlink.process_command(cmd='Unknown', data='Dont Care')
1622- log_text = '(127.0.0.1) Ignoring command="Unknown" (Invalid/Unknown)'
1623-
1624- # THEN: Error should be logged and no command called
1625- self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')
1626- mock_log.error.assert_called_once_with(log_text)
1627+ log_warning_text = [call('(111.111.111.111) Unable to process command="CLSS" (Future option?)')]
1628+ log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "Huh?"')]
1629+
1630+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1631+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1632+
1633+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1634+ pjlink.pjlink_functions = MagicMock()
1635+
1636+ # WHEN: Processing a possible future command
1637+ pjlink.process_command(cmd='CLSS', data="Huh?")
1638+
1639+ # THEN: Appropriate log entries should have been made and methods called/not called
1640+ mock_log.debug.assert_has_calls(log_debug_text)
1641+ mock_log.warning.assert_has_calls(log_warning_text)
1642+ assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions'
1643+ assert mock_process_clss.called is False, 'Should not have called process_clss'
1644
1645 def test_process_command_ok(self):
1646 """
1647 Test command returned success
1648 """
1649 # GIVEN: Initial mocks and data
1650- mock_log = patch.object(openlp.core.projectors.pjlink, 'log').start()
1651- mock_send_command = patch.object(self.pjlink_test, 'send_command').start()
1652-
1653- pjlink = self.pjlink_test
1654- log_text = '(111.111.111.111) Command "POWR" returned OK'
1655-
1656- # WHEN: process_command called with a command that returns OK
1657- pjlink.process_command(cmd='POWR', data='OK')
1658-
1659- # THEN: Appropriate calls should have been made
1660- mock_log.debug.assert_called_with(log_text)
1661- mock_send_command.assert_called_once_with(cmd='POWR')
1662+ # GIVEN: Test object and mocks
1663+ log_debug_calls = [call('(111.111.111.111) Processing command "CLSS" with data "OK"'),
1664+ call('(111.111.111.111) Command "CLSS" returned OK')]
1665+
1666+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1667+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
1668+ patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
1669+
1670+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1671+
1672+ # WHEN: process_command is called with valid function and data
1673+ pjlink.process_command(cmd='CLSS', data='OK')
1674+
1675+ # THEN: Appropriate log entries should have been made and methods called
1676+ mock_log.debug.assert_has_calls(log_debug_calls)
1677+ mock_send_command.assert_called_once_with(cmd='CLSS')
1678+ mock_process_clss.assert_not_called()
1679
1680=== modified file 'tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py'
1681--- tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py 2017-12-28 08:22:55 +0000
1682+++ tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py 2018-01-03 05:54:24 +0000
1683@@ -23,937 +23,1017 @@
1684 Package to test the openlp.core.projectors.pjlink commands package.
1685 """
1686 from unittest import TestCase
1687-from unittest.mock import patch
1688+from unittest.mock import call, patch
1689
1690 import openlp.core.projectors.pjlink
1691-from openlp.core.projectors.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \
1692- PJLINK_POWR_STATUS, \
1693- E_ERROR, E_NOT_CONNECTED, E_SOCKET_ADDRESS_NOT_AVAILABLE, E_UNKNOWN_SOCKET_ERROR, E_WARN, \
1694- S_CONNECTED, S_OFF, S_ON, S_NOT_CONNECTED, S_CONNECTING, S_STANDBY
1695+from openlp.core.projectors.constants import PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_POWR_STATUS, \
1696+ STATUS_CODE, STATUS_MSG, E_ERROR, E_NOT_CONNECTED, E_UNKNOWN_SOCKET_ERROR, E_WARN, \
1697+ S_CONNECTED, S_CONNECTING, S_OFF, S_OK, S_ON, S_NOT_CONNECTED, S_STANDBY
1698 from openlp.core.projectors.db import Projector
1699 from openlp.core.projectors.pjlink import PJLink
1700-from tests.resources.projector.data import TEST_PIN, TEST1_DATA
1701-
1702-pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
1703-pjlink_test.ip = '127.0.0.1'
1704-
1705-# Create a list of ERST positional data so we don't have to redo the same buildup multiple times
1706-PJLINK_ERST_POSITIONS = []
1707-for pos in range(0, len(PJLINK_ERST_DATA)):
1708- if pos in PJLINK_ERST_DATA:
1709- PJLINK_ERST_POSITIONS.append(PJLINK_ERST_DATA[pos])
1710+
1711+from tests.resources.projector.data import TEST1_DATA
1712
1713
1714 class TestPJLinkCommands(TestCase):
1715 """
1716 Tests for the PJLinkCommands class part 1
1717 """
1718- @patch.object(pjlink_test, 'changeStatus')
1719- @patch.object(openlp.core.projectors.pjlink, 'log')
1720- def test_projector_change_status_connection_error(self, mock_log, mock_change_status):
1721+ def test_projector_change_status_unknown_socket_error(self):
1722 """
1723 Test change_status with connection error
1724 """
1725- # GIVEN: Test object
1726- pjlink = pjlink_test
1727- pjlink.projector_status = 0
1728- pjlink.status_connect = 0
1729- test_code = E_UNKNOWN_SOCKET_ERROR
1730- mock_change_status.reset_mock()
1731- mock_log.reset_mock()
1732-
1733- # WHEN: change_status called with unknown socket error
1734- pjlink.change_status(status=test_code, msg=None)
1735-
1736- # THEN: Proper settings should change and signals sent
1737- self.assertEqual(pjlink.projector_status, E_NOT_CONNECTED, 'Projector status should be NOT CONNECTED')
1738- self.assertEqual(pjlink.status_connect, E_NOT_CONNECTED, 'Status connect should be NOT CONNECTED')
1739- mock_change_status.emit.assert_called_once_with(pjlink.ip, E_UNKNOWN_SOCKET_ERROR,
1740- 'An unidentified error occurred')
1741- self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
1742-
1743- @patch.object(pjlink_test, 'changeStatus')
1744- @patch.object(openlp.core.projectors.pjlink, 'log')
1745- def test_projector_change_status_connection_status_connecting(self, mock_log, mock_change_status):
1746- """
1747- Test change_status with connection status
1748- """
1749- # GIVEN: Test object
1750- pjlink = pjlink_test
1751- pjlink.projector_status = 0
1752- pjlink.status_connect = 0
1753- test_code = S_CONNECTING
1754- mock_change_status.reset_mock()
1755- mock_log.reset_mock()
1756-
1757- # WHEN: change_status called with unknown socket error
1758- pjlink.change_status(status=test_code, msg=None)
1759-
1760- # THEN: Proper settings should change and signals sent
1761- self.assertEqual(pjlink.projector_status, S_NOT_CONNECTED, 'Projector status should be NOT CONNECTED')
1762- self.assertEqual(pjlink.status_connect, S_CONNECTING, 'Status connect should be CONNECTING')
1763- mock_change_status.emit.assert_called_once_with(pjlink.ip, S_CONNECTING, 'Connecting')
1764- self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
1765-
1766- @patch.object(pjlink_test, 'changeStatus')
1767- @patch.object(openlp.core.projectors.pjlink, 'log')
1768- def test_projector_change_status_connection_status_connected(self, mock_log, mock_change_status):
1769- """
1770- Test change_status with connection status
1771- """
1772- # GIVEN: Test object
1773- pjlink = pjlink_test
1774- pjlink.projector_status = 0
1775- pjlink.status_connect = 0
1776- test_code = S_ON
1777- mock_change_status.reset_mock()
1778- mock_log.reset_mock()
1779-
1780- # WHEN: change_status called with unknown socket error
1781- pjlink.change_status(status=test_code, msg=None)
1782-
1783- # THEN: Proper settings should change and signals sent
1784- self.assertEqual(pjlink.projector_status, S_ON, 'Projector status should be ON')
1785- self.assertEqual(pjlink.status_connect, S_CONNECTED, 'Status connect should be CONNECTED')
1786- mock_change_status.emit.assert_called_once_with(pjlink.ip, S_ON, 'Power is on')
1787- self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
1788-
1789- @patch.object(pjlink_test, 'changeStatus')
1790- @patch.object(openlp.core.projectors.pjlink, 'log')
1791- def test_projector_change_status_connection_status_with_message(self, mock_log, mock_change_status):
1792- """
1793- Test change_status with connection status
1794- """
1795- # GIVEN: Test object
1796- pjlink = pjlink_test
1797- pjlink.projector_status = 0
1798- pjlink.status_connect = 0
1799+ log_debug_calls = [
1800+ call('(111.111.111.111) Changing status to '
1801+ '{status} "{msg}"'.format(status=STATUS_CODE[E_UNKNOWN_SOCKET_ERROR],
1802+ msg=STATUS_MSG[E_UNKNOWN_SOCKET_ERROR])),
1803+ call('(111.111.111.111) status_connect: '
1804+ '{code}: "{msg}"'.format(code=STATUS_CODE[E_NOT_CONNECTED],
1805+ msg=STATUS_MSG[E_NOT_CONNECTED])),
1806+ call('(111.111.111.111) projector_status: '
1807+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1808+ msg=STATUS_MSG[S_OK])),
1809+ call('(111.111.111.111) error_status: '
1810+ '{code}: "{msg}"'.format(code=STATUS_CODE[E_UNKNOWN_SOCKET_ERROR],
1811+ msg=STATUS_MSG[E_UNKNOWN_SOCKET_ERROR]))]
1812+
1813+ # GIVEN: Test object and mocks
1814+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1815+ patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus, \
1816+ patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
1817+
1818+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1819+ pjlink.projector_status = 0
1820+ pjlink.status_connect = 0
1821+
1822+ # WHEN: change_status called with unknown socket error
1823+ pjlink.change_status(status=E_UNKNOWN_SOCKET_ERROR)
1824+
1825+ # THEN: Proper settings should change and signals sent
1826+ mock_log.debug.assert_has_calls(log_debug_calls)
1827+ assert pjlink.projector_status == S_OK, 'Projector status should not have changed'
1828+ assert pjlink.status_connect == E_NOT_CONNECTED, 'Status connect should be NOT CONNECTED'
1829+ assert mock_UpdateIcons.emit.called is True, 'Should have called UpdateIcons'
1830+ mock_changeStatus.emit.assert_called_once_with(pjlink.ip, E_UNKNOWN_SOCKET_ERROR,
1831+ STATUS_MSG[E_UNKNOWN_SOCKET_ERROR])
1832+
1833+ def test_projector_change_status_connection_status_connecting(self):
1834+ """
1835+ Test change_status with connecting status
1836+ """
1837+ log_debug_calls = [
1838+ call('(111.111.111.111) Changing status to '
1839+ '{status} "{msg}"'.format(status=STATUS_CODE[S_CONNECTING],
1840+ msg=STATUS_MSG[S_CONNECTING])),
1841+ call('(111.111.111.111) status_connect: '
1842+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_CONNECTING],
1843+ msg=STATUS_MSG[S_CONNECTING])),
1844+ call('(111.111.111.111) projector_status: '
1845+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1846+ msg=STATUS_MSG[S_OK])),
1847+ call('(111.111.111.111) error_status: '
1848+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1849+ msg=STATUS_MSG[S_OK]))]
1850+
1851+ # GIVEN: Test object and mocks
1852+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1853+ patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus, \
1854+ patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
1855+
1856+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1857+ pjlink.projector_status = 0
1858+ pjlink.status_connect = 0
1859+
1860+ # WHEN: change_status called with CONNECTING
1861+ pjlink.change_status(status=S_CONNECTING)
1862+
1863+ # THEN: Proper settings should change and signals sent
1864+ mock_log.debug.assert_has_calls(log_debug_calls)
1865+ mock_changeStatus.emit.assert_called_once_with(pjlink.ip, S_CONNECTING, STATUS_MSG[S_CONNECTING])
1866+ assert pjlink.projector_status == S_OK, 'Projector status should not have changed'
1867+ assert pjlink.status_connect == S_CONNECTING, 'Status connect should be CONNECTING'
1868+ assert mock_UpdateIcons.emit.called is True, 'Should have called UpdateIcons'
1869+
1870+ def test_projector_change_status_connection_status_connected(self):
1871+ """
1872+ Test change_status with connected status
1873+ """
1874+ log_debug_calls = [
1875+ call('(111.111.111.111) Changing status to '
1876+ '{status} "{msg}"'.format(status=STATUS_CODE[S_CONNECTED],
1877+ msg=STATUS_MSG[S_CONNECTED])),
1878+ call('(111.111.111.111) status_connect: '
1879+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_CONNECTED],
1880+ msg=STATUS_MSG[S_CONNECTED])),
1881+ call('(111.111.111.111) projector_status: '
1882+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1883+ msg=STATUS_MSG[S_OK])),
1884+ call('(111.111.111.111) error_status: '
1885+ '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1886+ msg=STATUS_MSG[S_OK]))]
1887+
1888+ # GIVEN: Test object and mocks
1889+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1890+ patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus:
1891+
1892+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1893+ pjlink.projector_status = 0
1894+ pjlink.status_connect = 0
1895+
1896+ # WHEN: change_status called with CONNECTED
1897+ pjlink.change_status(status=S_CONNECTED)
1898+
1899+ # THEN: Proper settings should change and signals sent
1900+ mock_log.debug.assert_has_calls(log_debug_calls)
1901+ mock_changeStatus.emit.assert_called_once_with(pjlink.ip, S_CONNECTED, 'Connected')
1902+ assert pjlink.projector_status == S_OK, 'Projector status should not have changed'
1903+ assert pjlink.status_connect == S_CONNECTED, 'Status connect should be CONNECTED'
1904+
1905+ def test_projector_change_status_connection_status_with_message(self):
1906+ """
1907+ Test change_status with connection status
1908+ """
1909 test_message = 'Different Status Message than default'
1910- test_code = S_ON
1911- mock_change_status.reset_mock()
1912- mock_log.reset_mock()
1913-
1914- # WHEN: change_status called with unknown socket error
1915- pjlink.change_status(status=test_code, msg=test_message)
1916-
1917- # THEN: Proper settings should change and signals sent
1918- self.assertEqual(pjlink.projector_status, S_ON, 'Projector status should be ON')
1919- self.assertEqual(pjlink.status_connect, S_CONNECTED, 'Status connect should be CONNECTED')
1920- mock_change_status.emit.assert_called_once_with(pjlink.ip, S_ON, test_message)
1921- self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')
1922-
1923- @patch.object(pjlink_test, 'send_command')
1924- @patch.object(openlp.core.projectors.pjlink, 'log')
1925- def test_projector_get_av_mute_status(self, mock_log, mock_send_command):
1926+ log_debug_calls = [
1927+ call('(111.111.111.111) Changing status to {status} "{msg}"'.format(status=STATUS_CODE[S_ON],
1928+ msg=test_message)),
1929+ call('(111.111.111.111) status_connect: {code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1930+ msg=test_message)),
1931+ call('(111.111.111.111) projector_status: {code}: "{msg}"'.format(code=STATUS_CODE[S_ON],
1932+ msg=test_message)),
1933+ call('(111.111.111.111) error_status: {code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
1934+ msg=test_message))]
1935+
1936+ # GIVEN: Test object and mocks
1937+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1938+ patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus:
1939+
1940+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1941+ pjlink.projector_status = 0
1942+ pjlink.status_connect = 0
1943+
1944+ # WHEN: change_status called with projector ON status
1945+ pjlink.change_status(status=S_ON, msg=test_message)
1946+
1947+ # THEN: Proper settings should change and signals sent
1948+ mock_log.debug.assert_has_calls(log_debug_calls)
1949+ mock_changeStatus.emit.assert_called_once_with(pjlink.ip, S_ON, test_message)
1950+ assert pjlink.projector_status == S_ON, 'Projector status should be ON'
1951+ assert pjlink.status_connect == S_OK, 'Status connect should not have changed'
1952+
1953+ def test_projector_get_av_mute_status(self):
1954 """
1955 Test sending command to retrieve shutter/audio state
1956 """
1957- # GIVEN: Test object
1958- pjlink = pjlink_test
1959- mock_log.reset_mock()
1960- mock_send_command.reset_mock()
1961 test_data = 'AVMT'
1962- test_log = '(127.0.0.1) Sending AVMT command'
1963-
1964- # WHEN: get_av_mute_status is called
1965- pjlink.get_av_mute_status()
1966-
1967- # THEN: log data and send_command should have been called
1968- mock_log.debug.assert_called_once_with(test_log)
1969- mock_send_command.assert_called_once_with(cmd=test_data)
1970-
1971- @patch.object(pjlink_test, 'send_command')
1972- @patch.object(openlp.core.projectors.pjlink, 'log')
1973- def test_projector_get_available_inputs(self, mock_log, mock_send_command):
1974+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
1975+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
1976+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
1977+
1978+ # GIVEN: Test object and mocks
1979+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
1980+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
1981+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1982+
1983+ # WHEN: get_av_mute_status is called
1984+ pjlink.get_av_mute_status()
1985+
1986+ # THEN: log data and send_command should have been called
1987+ mock_log.debug.assert_has_calls(log_debug_calls)
1988+ mock_send_command.assert_called_once_with(cmd=test_data)
1989+
1990+ def test_projector_get_available_inputs(self):
1991 """
1992 Test sending command to retrieve avaliable inputs
1993 """
1994- # GIVEN: Test object
1995- pjlink = pjlink_test
1996- mock_log.reset_mock()
1997- mock_send_command.reset_mock()
1998 test_data = 'INST'
1999- test_log = '(127.0.0.1) Sending INST command'
2000-
2001- # WHEN: get_available_inputs is called
2002- pjlink.get_available_inputs()
2003-
2004- # THEN: log data and send_command should have been called
2005- mock_log.debug.assert_called_once_with(test_log)
2006- mock_send_command.assert_called_once_with(cmd=test_data)
2007-
2008- @patch.object(pjlink_test, 'send_command')
2009- @patch.object(openlp.core.projectors.pjlink, 'log')
2010- def test_projector_get_error_status(self, mock_log, mock_send_command):
2011+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2012+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2013+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2014+
2015+ # GIVEN: Test object and mocks
2016+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2017+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2018+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2019+
2020+ # WHEN: get_available_inputs is called
2021+ pjlink.get_available_inputs()
2022+
2023+ # THEN: log data and send_command should have been called
2024+ mock_log.debug.assert_has_calls(log_debug_calls)
2025+ mock_send_command.assert_called_once_with(cmd=test_data)
2026+
2027+ def test_projector_get_error_status(self):
2028 """
2029 Test sending command to retrieve projector error status
2030 """
2031- # GIVEN: Test object
2032- pjlink = pjlink_test
2033- mock_log.reset_mock()
2034- mock_send_command.reset_mock()
2035 test_data = 'ERST'
2036- test_log = '(127.0.0.1) Sending ERST command'
2037-
2038- # WHEN: get_error_status is called
2039- pjlink.get_error_status()
2040-
2041- # THEN: log data and send_command should have been called
2042- mock_log.debug.assert_called_once_with(test_log)
2043- mock_send_command.assert_called_once_with(cmd=test_data)
2044-
2045- @patch.object(pjlink_test, 'send_command')
2046- @patch.object(openlp.core.projectors.pjlink, 'log')
2047- def test_projector_get_input_source(self, mock_log, mock_send_command):
2048+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2049+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2050+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2051+ # GIVEN: Test object and mocks
2052+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2053+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2054+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2055+
2056+ # WHEN: get_error_status is called
2057+ pjlink.get_error_status()
2058+
2059+ # THEN: log data and send_command should have been called
2060+ mock_log.debug.assert_has_calls(log_debug_calls)
2061+ mock_send_command.assert_called_once_with(cmd=test_data)
2062+
2063+ def test_projector_get_input_source(self):
2064 """
2065 Test sending command to retrieve current input
2066 """
2067- # GIVEN: Test object
2068- pjlink = pjlink_test
2069- mock_log.reset_mock()
2070- mock_send_command.reset_mock()
2071 test_data = 'INPT'
2072- test_log = '(127.0.0.1) Sending INPT command'
2073-
2074- # WHEN: get_input_source is called
2075- pjlink.get_input_source()
2076-
2077- # THEN: log data and send_command should have been called
2078- mock_log.debug.assert_called_once_with(test_log)
2079- mock_send_command.assert_called_once_with(cmd=test_data)
2080-
2081- @patch.object(pjlink_test, 'send_command')
2082- @patch.object(openlp.core.projectors.pjlink, 'log')
2083- def test_projector_get_lamp_status(self, mock_log, mock_send_command):
2084+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2085+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2086+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2087+
2088+ # GIVEN: Test object and mocks
2089+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2090+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2091+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2092+
2093+ # WHEN: get_input_source is called
2094+ pjlink.get_input_source()
2095+
2096+ # THEN: log data and send_command should have been called
2097+ mock_log.debug.assert_has_calls(log_debug_calls)
2098+ mock_send_command.assert_called_once_with(cmd=test_data)
2099+
2100+ def test_projector_get_lamp_status(self):
2101 """
2102 Test sending command to retrieve lamp(s) status
2103 """
2104- # GIVEN: Test object
2105- pjlink = pjlink_test
2106- mock_log.reset_mock()
2107- mock_send_command.reset_mock()
2108 test_data = 'LAMP'
2109- test_log = '(127.0.0.1) Sending LAMP command'
2110-
2111- # WHEN: get_lamp_status is called
2112- pjlink.get_lamp_status()
2113-
2114- # THEN: log data and send_command should have been called
2115- mock_log.debug.assert_called_once_with(test_log)
2116- mock_send_command.assert_called_once_with(cmd=test_data)
2117-
2118- @patch.object(pjlink_test, 'send_command')
2119- @patch.object(openlp.core.projectors.pjlink, 'log')
2120- def test_projector_get_manufacturer(self, mock_log, mock_send_command):
2121+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2122+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2123+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2124+
2125+ # GIVEN: Test object and mocks
2126+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2127+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2128+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2129+
2130+ # WHEN: get_input_source is called
2131+ pjlink.get_lamp_status()
2132+
2133+ # THEN: log data and send_command should have been called
2134+ mock_log.debug.assert_has_calls(log_debug_calls)
2135+ mock_send_command.assert_called_once_with(cmd=test_data)
2136+
2137+ def test_projector_get_manufacturer(self):
2138 """
2139 Test sending command to retrieve manufacturer name
2140 """
2141- # GIVEN: Test object
2142- pjlink = pjlink_test
2143- mock_log.reset_mock()
2144- mock_send_command.reset_mock()
2145 test_data = 'INF1'
2146- test_log = '(127.0.0.1) Sending INF1 command'
2147-
2148- # WHEN: get_manufacturer is called
2149- pjlink.get_manufacturer()
2150-
2151- # THEN: log data and send_command should have been called
2152- mock_log.debug.assert_called_once_with(test_log)
2153- mock_send_command.assert_called_once_with(cmd=test_data)
2154-
2155- @patch.object(pjlink_test, 'send_command')
2156- @patch.object(openlp.core.projectors.pjlink, 'log')
2157- def test_projector_get_model(self, mock_log, mock_send_command):
2158+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2159+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2160+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2161+
2162+ # GIVEN: Test object and mocks
2163+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2164+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2165+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2166+
2167+ # WHEN: get_input_source is called
2168+ pjlink.get_manufacturer()
2169+
2170+ # THEN: log data and send_command should have been called
2171+ mock_log.debug.assert_has_calls(log_debug_calls)
2172+ mock_send_command.assert_called_once_with(cmd=test_data)
2173+
2174+ def test_projector_get_model(self):
2175 """
2176 Test sending command to get model information
2177 """
2178- # GIVEN: Test object
2179- pjlink = pjlink_test
2180- mock_log.reset_mock()
2181- mock_send_command.reset_mock()
2182 test_data = 'INF2'
2183- test_log = '(127.0.0.1) Sending INF2 command'
2184-
2185- # WHEN: get_model is called
2186- pjlink.get_model()
2187-
2188- # THEN: log data and send_command should have been called
2189- mock_log.debug.assert_called_once_with(test_log)
2190- mock_send_command.assert_called_once_with(cmd=test_data)
2191-
2192- @patch.object(pjlink_test, 'send_command')
2193- @patch.object(openlp.core.projectors.pjlink, 'log')
2194- def test_projector_get_name(self, mock_log, mock_send_command):
2195+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2196+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2197+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2198+
2199+ # GIVEN: Test object and mocks
2200+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2201+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2202+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2203+
2204+ # WHEN: get_input_source is called
2205+ pjlink.get_model()
2206+
2207+ # THEN: log data and send_command should have been called
2208+ mock_log.debug.assert_has_calls(log_debug_calls)
2209+ mock_send_command.assert_called_once_with(cmd=test_data)
2210+
2211+ def test_projector_get_name(self):
2212 """
2213 Test sending command to get user-assigned name
2214 """
2215- # GIVEN: Test object
2216- pjlink = pjlink_test
2217- mock_log.reset_mock()
2218- mock_send_command.reset_mock()
2219 test_data = 'NAME'
2220- test_log = '(127.0.0.1) Sending NAME command'
2221-
2222- # WHEN: get_name is called
2223- pjlink.get_name()
2224-
2225- # THEN: log data and send_command should have been called
2226- mock_log.debug.assert_called_once_with(test_log)
2227- mock_send_command.assert_called_once_with(cmd=test_data)
2228-
2229- @patch.object(pjlink_test, 'send_command')
2230- @patch.object(openlp.core.projectors.pjlink, 'log')
2231- def test_projector_get_other_info(self, mock_log, mock_send_command):
2232+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2233+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2234+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2235+
2236+ # GIVEN: Test object and mocks
2237+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2238+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2239+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2240+
2241+ # WHEN: get_input_source is called
2242+ pjlink.get_name()
2243+
2244+ # THEN: log data and send_command should have been called
2245+ mock_log.debug.assert_has_calls(log_debug_calls)
2246+ mock_send_command.assert_called_once_with(cmd=test_data)
2247+
2248+ def test_projector_get_other_info(self):
2249 """
2250 Test sending command to retrieve other information
2251 """
2252- # GIVEN: Test object
2253- pjlink = pjlink_test
2254- mock_log.reset_mock()
2255- mock_send_command.reset_mock()
2256 test_data = 'INFO'
2257- test_log = '(127.0.0.1) Sending INFO command'
2258-
2259- # WHEN: get_other_info is called
2260- pjlink.get_other_info()
2261-
2262- # THEN: log data and send_command should have been called
2263- mock_log.debug.assert_called_once_with(test_log)
2264- mock_send_command.assert_called_once_with(cmd=test_data)
2265-
2266- @patch.object(pjlink_test, 'send_command')
2267- @patch.object(openlp.core.projectors.pjlink, 'log')
2268- def test_projector_get_power_status(self, mock_log, mock_send_command):
2269+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2270+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2271+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2272+
2273+ # GIVEN: Test object and mocks
2274+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2275+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2276+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2277+
2278+ # WHEN: get_input_source is called
2279+ pjlink.get_other_info()
2280+
2281+ # THEN: log data and send_command should have been called
2282+ mock_log.debug.assert_has_calls(log_debug_calls)
2283+ mock_send_command.assert_called_once_with(cmd=test_data)
2284+
2285+ def test_projector_get_power_status(self):
2286 """
2287 Test sending command to retrieve current power state
2288 """
2289- # GIVEN: Test object
2290- pjlink = pjlink_test
2291- mock_log.reset_mock()
2292- mock_send_command.reset_mock()
2293 test_data = 'POWR'
2294- test_log = '(127.0.0.1) Sending POWR command'
2295-
2296- # WHEN: get_power_status called
2297- pjlink.get_power_status()
2298-
2299- # THEN: log data and send_command should have been called
2300- mock_log.debug.assert_called_once_with(test_log)
2301- mock_send_command.assert_called_once_with(cmd=test_data)
2302-
2303- def test_projector_get_status_error(self):
2304- """
2305- Test to check returned information for error code
2306- """
2307- # GIVEN: Test object
2308- pjlink = pjlink_test
2309- test_string = 'E_SOCKET_ADDRESS_NOT_AVAILABLE'
2310- test_message = 'The address specified to socket.bind() does not belong to the host'
2311-
2312- # WHEN: get_status called
2313- string, message = pjlink._get_status(status=E_SOCKET_ADDRESS_NOT_AVAILABLE)
2314-
2315- # THEN: Proper strings should have been returned
2316- self.assertEqual(string, test_string, 'Code as string should have been returned')
2317- self.assertEqual(message, test_message, 'Description of code should have been returned')
2318+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2319+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2320+ call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
2321+
2322+ # GIVEN: Test object and mocks
2323+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
2324+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
2325+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2326+
2327+ # WHEN: get_input_source is called
2328+ pjlink.get_power_status()
2329+
2330+ # THEN: log data and send_command should have been called
2331+ mock_log.debug.assert_has_calls(log_debug_calls)
2332+ mock_send_command.assert_called_once_with(cmd=test_data)
2333
2334 def test_projector_get_status_invalid(self):
2335 """
2336 Test to check returned information for error code
2337 """
2338 # GIVEN: Test object
2339- pjlink = pjlink_test
2340- test_string = 'Test string since get_status will only work with int'
2341- test_message = 'Invalid status code'
2342+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2343+ test_string = 'NaN test'
2344
2345 # WHEN: get_status called
2346- string, message = pjlink._get_status(status=test_string)
2347-
2348- # THEN: Proper strings should have been returned
2349- self.assertEqual(string, -1, 'Should have returned -1 as a bad status check')
2350- self.assertEqual(message, test_message, 'Error message should have been returned')
2351-
2352- def test_projector_get_status_status(self):
2353+ code, message = pjlink._get_status(status=test_string)
2354+
2355+ # THEN: Proper data should have been returned
2356+ assert code == -1, 'Should have returned -1 as a bad status check'
2357+ assert message is None, 'Invalid code type should have returned None for message'
2358+
2359+ def test_projector_get_status_valid(self):
2360 """
2361 Test to check returned information for status codes
2362 """
2363 # GIVEN: Test object
2364- pjlink = pjlink_test
2365- test_string = 'S_NOT_CONNECTED'
2366- test_message = 'Not connected'
2367+ test_message = 'Not Connected'
2368+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2369
2370 # WHEN: get_status called
2371- string, message = pjlink._get_status(status=S_NOT_CONNECTED)
2372+ code, message = pjlink._get_status(status=S_NOT_CONNECTED)
2373
2374 # THEN: Proper strings should have been returned
2375- self.assertEqual(string, test_string, 'Code as string should have been returned')
2376- self.assertEqual(message, test_message, 'Description of code should have been returned')
2377+ assert code == 'S_NOT_CONNECTED', 'Code returned should have been the same code that was sent'
2378+ assert message == test_message, 'Description of code should have been returned'
2379
2380 def test_projector_get_status_unknown(self):
2381 """
2382 Test to check returned information for unknown code
2383 """
2384 # GIVEN: Test object
2385- pjlink = pjlink_test
2386- test_string = 999999
2387- test_message = 'Unknown status'
2388+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2389
2390 # WHEN: get_status called
2391- string, message = pjlink._get_status(status=test_string)
2392+ code, message = pjlink._get_status(status=9999)
2393
2394 # THEN: Proper strings should have been returned
2395- self.assertEqual(string, test_string, 'Received code should have been returned')
2396- self.assertEqual(message, test_message, 'Unknown status string should have been returned')
2397+ assert code is None, 'Code returned should have been the same code that was sent'
2398+ assert message is None, 'Should have returned None as message'
2399
2400 def test_projector_process_inf1(self):
2401 """
2402 Test saving INF1 data (manufacturer)
2403 """
2404+ test_data = 'TEst INformation MultiCase'
2405+
2406 # GIVEN: Test object
2407- pjlink = pjlink_test
2408+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2409 pjlink.manufacturer = None
2410- test_data = 'TEst INformation MultiCase'
2411
2412 # WHEN: process_inf called with test data
2413 pjlink.process_inf1(data=test_data)
2414
2415 # THEN: Data should be saved
2416- self.assertEqual(pjlink.manufacturer, test_data, 'Test data should have been saved')
2417+ assert pjlink.manufacturer == test_data, 'Test data should have been saved'
2418
2419 def test_projector_process_inf2(self):
2420 """
2421 Test saving INF2 data (model)
2422 """
2423+ test_data = 'TEst moDEl MultiCase'
2424+
2425 # GIVEN: Test object
2426- pjlink = pjlink_test
2427+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2428 pjlink.model = None
2429- test_data = 'TEst moDEl MultiCase'
2430
2431 # WHEN: process_inf called with test data
2432 pjlink.process_inf2(data=test_data)
2433
2434 # THEN: Data should be saved
2435- self.assertEqual(pjlink.model, test_data, 'Test data should have been saved')
2436+ assert pjlink.model == test_data, 'Test data should have been saved'
2437
2438 def test_projector_process_info(self):
2439 """
2440 Test saving INFO data (other information)
2441 """
2442+ test_data = 'TEst ExtrANEous MultiCase INformatoin that MFGR might Set'
2443+
2444 # GIVEN: Test object
2445- pjlink = pjlink_test
2446+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2447 pjlink.other_info = None
2448- test_data = 'TEst ExtrANEous MultiCase INformatoin that MFGR might Set'
2449
2450 # WHEN: process_inf called with test data
2451 pjlink.process_info(data=test_data)
2452
2453 # THEN: Data should be saved
2454- self.assertEqual(pjlink.other_info, test_data, 'Test data should have been saved')
2455+ assert pjlink.other_info == test_data, 'Test data should have been saved'
2456
2457- @patch.object(pjlink_test, 'projectorUpdateIcons')
2458- def test_projector_process_avmt_bad_data(self, mock_UpdateIcons):
2459+ def test_projector_process_avmt_bad_data(self):
2460 """
2461 Test avmt bad data fail
2462 """
2463 # GIVEN: Test object
2464- pjlink = pjlink_test
2465- pjlink.shutter = True
2466- pjlink.mute = True
2467-
2468- # WHEN: Called with an invalid setting
2469- pjlink.process_avmt('36')
2470-
2471- # THEN: Shutter should be closed and mute should be True
2472- self.assertTrue(pjlink.shutter, 'Shutter should changed')
2473- self.assertTrue(pjlink.mute, 'Audio should not have changed')
2474- self.assertFalse(mock_UpdateIcons.emit.called, 'Update icons should NOT have been called')
2475-
2476- @patch.object(pjlink_test, 'projectorUpdateIcons')
2477- def test_projector_process_avmt_closed_muted(self, mock_UpdateIcons):
2478+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
2479+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2480+ pjlink.shutter = True
2481+ pjlink.mute = True
2482+
2483+ # WHEN: Called with an invalid setting
2484+ pjlink.process_avmt('36')
2485+
2486+ # THEN: Shutter should be closed and mute should be True
2487+ assert pjlink.shutter is True, 'Shutter should changed'
2488+ assert pjlink.mute is True, 'Audio should not have changed'
2489+ assert mock_UpdateIcons.emit.called is False, 'Update icons should NOT have been called'
2490+
2491+ def test_projector_process_avmt_closed_muted(self):
2492 """
2493 Test avmt status shutter closed and mute off
2494 """
2495 # GIVEN: Test object
2496- pjlink = pjlink_test
2497- pjlink.shutter = False
2498- pjlink.mute = False
2499-
2500- # WHEN: Called with setting shutter to closed and mute on
2501- pjlink.process_avmt('31')
2502-
2503- # THEN: Shutter should be closed and mute should be True
2504- self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')
2505- self.assertTrue(pjlink.mute, 'Audio should be muted')
2506- self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')
2507-
2508- @patch.object(pjlink_test, 'projectorUpdateIcons')
2509- def test_projector_process_avmt_shutter_closed(self, mock_UpdateIcons):
2510+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
2511+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2512+ pjlink.shutter = False
2513+ pjlink.mute = False
2514+
2515+ # WHEN: Called with setting shutter to closed and mute on
2516+ pjlink.process_avmt('31')
2517+
2518+ # THEN: Shutter should be closed and mute should be True
2519+ assert pjlink.shutter is True, 'Shutter should have been set to closed'
2520+ assert pjlink.mute is True, 'Audio should be muted'
2521+ assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
2522+
2523+ def test_projector_process_avmt_shutter_closed(self):
2524 """
2525 Test avmt status shutter closed and audio unchanged
2526 """
2527 # GIVEN: Test object
2528- pjlink = pjlink_test
2529- pjlink.shutter = False
2530- pjlink.mute = True
2531-
2532- # WHEN: Called with setting shutter closed and mute off
2533- pjlink.process_avmt('11')
2534-
2535- # THEN: Shutter should be True and mute should be False
2536- self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')
2537- self.assertTrue(pjlink.mute, 'Audio should not have changed')
2538- self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')
2539-
2540- @patch.object(pjlink_test, 'projectorUpdateIcons')
2541- def test_projector_process_avmt_audio_muted(self, mock_UpdateIcons):
2542+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
2543+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2544+ pjlink.shutter = False
2545+ pjlink.mute = True
2546+
2547+ # WHEN: Called with setting shutter closed and mute off
2548+ pjlink.process_avmt('11')
2549+
2550+ # THEN: Shutter should be True and mute should be False
2551+ assert pjlink.shutter is True, 'Shutter should have been set to closed'
2552+ assert pjlink.mute is True, 'Audio should not have changed'
2553+ assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
2554+
2555+ def test_projector_process_avmt_audio_muted(self):
2556 """
2557 Test avmt status shutter unchanged and mute on
2558 """
2559 # GIVEN: Test object
2560- pjlink = pjlink_test
2561- pjlink.shutter = True
2562- pjlink.mute = False
2563-
2564- # WHEN: Called with setting shutter closed and mute on
2565- pjlink.process_avmt('21')
2566-
2567- # THEN: Shutter should be closed and mute should be True
2568- self.assertTrue(pjlink.shutter, 'Shutter should not have changed')
2569- self.assertTrue(pjlink.mute, 'Audio should be off')
2570- self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')
2571-
2572- @patch.object(pjlink_test, 'projectorUpdateIcons')
2573- def test_projector_process_avmt_open_unmuted(self, mock_UpdateIcons):
2574+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
2575+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2576+ pjlink.shutter = True
2577+ pjlink.mute = False
2578+
2579+ # WHEN: Called with setting shutter closed and mute on
2580+ pjlink.process_avmt('21')
2581+
2582+ # THEN: Shutter should be closed and mute should be True
2583+ assert pjlink.shutter is True, 'Shutter should not have changed'
2584+ assert pjlink.mute is True, 'Audio should be off'
2585+ assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
2586+
2587+ def test_projector_process_avmt_open_unmuted(self):
2588 """
2589 Test avmt status shutter open and mute off
2590 """
2591 # GIVEN: Test object
2592- pjlink = pjlink_test
2593- pjlink.shutter = True
2594- pjlink.mute = True
2595-
2596- # WHEN: Called with setting shutter to closed and mute on
2597- pjlink.process_avmt('30')
2598-
2599- # THEN: Shutter should be closed and mute should be True
2600- self.assertFalse(pjlink.shutter, 'Shutter should have been set to open')
2601- self.assertFalse(pjlink.mute, 'Audio should be on')
2602- self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')
2603+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
2604+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2605+ pjlink.shutter = True
2606+ pjlink.mute = True
2607+
2608+ # WHEN: Called with setting shutter to closed and mute on
2609+ pjlink.process_avmt('30')
2610+
2611+ # THEN: Shutter should be closed and mute should be True
2612+ assert pjlink.shutter is False, 'Shutter should have been set to open'
2613+ assert pjlink.mute is False, 'Audio should be on'
2614+ assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
2615
2616 def test_projector_process_clss_one(self):
2617 """
2618 Test class 1 sent from projector
2619 """
2620 # GIVEN: Test object
2621- pjlink = pjlink_test
2622+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2623
2624 # WHEN: Process class response
2625 pjlink.process_clss('1')
2626
2627 # THEN: Projector class should be set to 1
2628- self.assertEqual(pjlink.pjlink_class, '1',
2629- 'Projector should have set class=1')
2630+ assert pjlink.pjlink_class == '1', 'Projector should have set class=1'
2631
2632 def test_projector_process_clss_two(self):
2633 """
2634 Test class 2 sent from projector
2635 """
2636 # GIVEN: Test object
2637- pjlink = pjlink_test
2638+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2639
2640 # WHEN: Process class response
2641 pjlink.process_clss('2')
2642
2643 # THEN: Projector class should be set to 1
2644- self.assertEqual(pjlink.pjlink_class, '2',
2645- 'Projector should have set class=2')
2646-
2647- @patch.object(openlp.core.projectors.pjlink, 'log')
2648- def test_projector_process_clss_invalid_nan(self, mock_log):
2649- """
2650- Test CLSS reply has no class number
2651- """
2652- # GIVEN: Test object
2653- pjlink = pjlink_test
2654-
2655- # WHEN: Process invalid reply
2656- pjlink.process_clss('Z')
2657- log_text = '(127.0.0.1) NAN CLSS version reply "Z" - defaulting to class "1"'
2658-
2659- # THEN: Projector class should be set with default value
2660- self.assertEqual(pjlink.pjlink_class, '1',
2661- 'Non-standard class reply should have set class=1')
2662- mock_log.error.assert_called_once_with(log_text)
2663-
2664- @patch.object(openlp.core.projectors.pjlink, 'log')
2665- def test_projector_process_clss_invalid_no_version(self, mock_log):
2666- """
2667- Test CLSS reply has no class number
2668- """
2669- # GIVEN: Test object
2670- pjlink = pjlink_test
2671-
2672- # WHEN: Process invalid reply
2673- pjlink.process_clss('Invalid')
2674- log_text = '(127.0.0.1) No numbers found in class version reply "Invalid" - defaulting to class "1"'
2675-
2676- # THEN: Projector class should be set with default value
2677- self.assertEqual(pjlink.pjlink_class, '1',
2678- 'Non-standard class reply should have set class=1')
2679- mock_log.error.assert_called_once_with(log_text)
2680+ assert pjlink.pjlink_class == '2', 'Projector should have set class=2'
2681+
2682+ def test_projector_process_clss_invalid_nan(self):
2683+ """
2684+ Test CLSS reply has no class number
2685+ """
2686+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2687+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2688+ call('(111.111.111.111) Setting pjlink_class for this projector to "1"')]
2689+ log_error_calls = [call('(111.111.111.111) NAN CLSS version reply "Z" - defaulting to class "1"')]
2690+
2691+ # GIVEN: Test object
2692+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
2693+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2694+
2695+ # WHEN: Process invalid reply
2696+ pjlink.process_clss('Z')
2697+
2698+ # THEN: Projector class should be set with default value
2699+ assert pjlink.pjlink_class == '1', 'Invalid NaN class reply should have set class=1'
2700+ mock_log.error.assert_has_calls(log_error_calls)
2701+ mock_log.debug.assert_has_calls(log_debug_calls)
2702+
2703+ def test_projector_process_clss_invalid_no_version(self):
2704+ """
2705+ Test CLSS reply has no class number
2706+ """
2707+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2708+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
2709+ call('(111.111.111.111) Setting pjlink_class for this projector to "1"')]
2710+ log_error_calls = [call('(111.111.111.111) No numbers found in class version reply "Invalid" '
2711+ '- defaulting to class "1"')]
2712+
2713+ # GIVEN: Test object
2714+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
2715+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2716+
2717+ # WHEN: Process invalid reply
2718+ pjlink.process_clss('Invalid')
2719+
2720+ # THEN: Projector class should be set with default value
2721+ assert pjlink.pjlink_class == '1', 'Invalid class reply should have set class=1'
2722+ mock_log.error.assert_has_calls(log_error_calls)
2723+ mock_log.debug.assert_has_calls(log_debug_calls)
2724
2725 def test_projector_process_erst_all_ok(self):
2726 """
2727- Test test_projector_process_erst_all_ok
2728+ Test to verify pjlink.projector_errors is set to None when no errors
2729 """
2730+ chk_data = '0' * PJLINK_ERST_DATA['DATA_LENGTH']
2731+
2732 # GIVEN: Test object
2733- pjlink = pjlink_test
2734- chk_test = PJLINK_ERST_STATUS['OK']
2735- chk_param = chk_test * len(PJLINK_ERST_POSITIONS)
2736+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2737
2738 # WHEN: process_erst with no errors
2739- pjlink.process_erst(chk_param)
2740+ pjlink.process_erst(chk_data)
2741
2742 # THEN: PJLink instance errors should be None
2743- self.assertIsNone(pjlink.projector_errors, 'projector_errors should have been set to None')
2744+ assert pjlink.projector_errors is None, 'projector_errors should have been set to None'
2745
2746- @patch.object(openlp.core.projectors.pjlink, 'log')
2747- def test_projector_process_erst_data_invalid_length(self, mock_log):
2748+ def test_projector_process_erst_data_invalid_length(self):
2749 """
2750 Test test_projector_process_erst_data_invalid_length
2751 """
2752+ chk_data = '0' * (PJLINK_ERST_DATA['DATA_LENGTH'] + 1)
2753+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2754+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED]))]
2755+ log_warn_calls = [call('111.111.111.111) Invalid error status response "0000000": '
2756+ 'length != {chk}'.format(chk=PJLINK_ERST_DATA['DATA_LENGTH']))]
2757+
2758 # GIVEN: Test object
2759- pjlink = pjlink_test
2760- pjlink.projector_errors = None
2761- log_text = '127.0.0.1) Invalid error status response "11111111": length != 6'
2762-
2763- # WHEN: process_erst called with invalid data (too many values
2764- pjlink.process_erst('11111111')
2765-
2766- # THEN: pjlink.projector_errors should be empty and warning logged
2767- self.assertIsNone(pjlink.projector_errors, 'There should be no errors')
2768- self.assertTrue(mock_log.warning.called, 'Warning should have been logged')
2769- mock_log.warning.assert_called_once_with(log_text)
2770-
2771- @patch.object(openlp.core.projectors.pjlink, 'log')
2772- def test_projector_process_erst_data_invalid_nan(self, mock_log):
2773+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
2774+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2775+ pjlink.projector_errors = None
2776+
2777+ # WHEN: process_erst called with invalid data (too many values
2778+ pjlink.process_erst(chk_data)
2779+
2780+ # THEN: pjlink.projector_errors should be empty and warning logged
2781+ assert pjlink.projector_errors is None, 'There should be no errors'
2782+ mock_log.debug.assert_has_calls(log_debug_calls)
2783+ mock_log.warning.assert_has_calls(log_warn_calls)
2784+
2785+ def test_projector_process_erst_data_invalid_nan(self):
2786 """
2787 Test test_projector_process_erst_data_invalid_nan
2788 """
2789+ chk_data = 'Z' + ('0' * (PJLINK_ERST_DATA['DATA_LENGTH'] - 1))
2790+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
2791+ '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED]))]
2792+ log_warn_calls = [call('(111.111.111.111) Invalid error status response "Z00000"')]
2793+
2794 # GIVEN: Test object
2795- pjlink = pjlink_test
2796- pjlink.projector_errors = None
2797- log_text = '(127.0.0.1) Invalid error status response "1111Z1"'
2798-
2799- # WHEN: process_erst called with invalid data (too many values
2800- pjlink.process_erst('1111Z1')
2801-
2802- # THEN: pjlink.projector_errors should be empty and warning logged
2803- self.assertIsNone(pjlink.projector_errors, 'There should be no errors')
2804- self.assertTrue(mock_log.warning.called, 'Warning should have been logged')
2805- mock_log.warning.assert_called_once_with(log_text)
2806+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
2807+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2808+ pjlink.projector_errors = None
2809+
2810+ # WHEN: process_erst called with invalid data (too many values
2811+ pjlink.process_erst(chk_data)
2812+
2813+ # THEN: pjlink.projector_errors should be empty and warning logged
2814+ assert pjlink.projector_errors is None, 'There should be no errors'
2815+ mock_log.debug.assert_has_calls(log_debug_calls)
2816+ mock_log.warning.assert_has_calls(log_warn_calls)
2817
2818 def test_projector_process_erst_all_warn(self):
2819 """
2820 Test test_projector_process_erst_all_warn
2821 """
2822+ chk_data = '{fan}{lamp}{temp}{cover}{filt}{other}'.format(fan=PJLINK_ERST_STATUS[E_WARN],
2823+ lamp=PJLINK_ERST_STATUS[E_WARN],
2824+ temp=PJLINK_ERST_STATUS[E_WARN],
2825+ cover=PJLINK_ERST_STATUS[E_WARN],
2826+ filt=PJLINK_ERST_STATUS[E_WARN],
2827+ other=PJLINK_ERST_STATUS[E_WARN])
2828+ chk_test = {'Fan': E_WARN,
2829+ 'Lamp': E_WARN,
2830+ 'Temperature': E_WARN,
2831+ 'Cover': E_WARN,
2832+ 'Filter': E_WARN,
2833+ 'Other': E_WARN}
2834+
2835 # GIVEN: Test object
2836- pjlink = pjlink_test
2837- chk_test = PJLINK_ERST_STATUS[E_WARN]
2838- chk_string = ERROR_STRING[E_WARN]
2839- chk_param = chk_test * len(PJLINK_ERST_POSITIONS)
2840+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2841+ pjlink.projector_errors = None
2842
2843 # WHEN: process_erst with status set to WARN
2844- pjlink.process_erst(chk_param)
2845+ pjlink.process_erst(chk_data)
2846
2847 # THEN: PJLink instance errors should match chk_value
2848- for chk in pjlink.projector_errors:
2849- self.assertEqual(pjlink.projector_errors[chk], chk_string,
2850- 'projector_errors["{chk}"] should have been set to "{err}"'.format(chk=chk,
2851- err=chk_string))
2852+ assert pjlink.projector_errors == chk_test, 'Projector errors should be all E_WARN'
2853
2854 def test_projector_process_erst_all_error(self):
2855 """
2856 Test test_projector_process_erst_all_error
2857 """
2858+ chk_data = '{fan}{lamp}{temp}{cover}{filt}{other}'.format(fan=PJLINK_ERST_STATUS[E_ERROR],
2859+ lamp=PJLINK_ERST_STATUS[E_ERROR],
2860+ temp=PJLINK_ERST_STATUS[E_ERROR],
2861+ cover=PJLINK_ERST_STATUS[E_ERROR],
2862+ filt=PJLINK_ERST_STATUS[E_ERROR],
2863+ other=PJLINK_ERST_STATUS[E_ERROR])
2864+ chk_test = {'Fan': E_ERROR,
2865+ 'Lamp': E_ERROR,
2866+ 'Temperature': E_ERROR,
2867+ 'Cover': E_ERROR,
2868+ 'Filter': E_ERROR,
2869+ 'Other': E_ERROR}
2870+
2871 # GIVEN: Test object
2872- pjlink = pjlink_test
2873- chk_test = PJLINK_ERST_STATUS[E_ERROR]
2874- chk_string = ERROR_STRING[E_ERROR]
2875- chk_param = chk_test * len(PJLINK_ERST_POSITIONS)
2876+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2877+ pjlink.projector_errors = None
2878
2879 # WHEN: process_erst with status set to WARN
2880- pjlink.process_erst(chk_param)
2881+ pjlink.process_erst(chk_data)
2882
2883 # THEN: PJLink instance errors should match chk_value
2884- for chk in pjlink.projector_errors:
2885- self.assertEqual(pjlink.projector_errors[chk], chk_string,
2886- 'projector_errors["{chk}"] should have been set to "{err}"'.format(chk=chk,
2887- err=chk_string))
2888+ assert pjlink.projector_errors == chk_test, 'Projector errors should be all E_ERROR'
2889
2890 def test_projector_process_erst_warn_cover_only(self):
2891 """
2892 Test test_projector_process_erst_warn_cover_only
2893 """
2894+ chk_data = '{fan}{lamp}{temp}{cover}{filt}{other}'.format(fan=PJLINK_ERST_STATUS[S_OK],
2895+ lamp=PJLINK_ERST_STATUS[S_OK],
2896+ temp=PJLINK_ERST_STATUS[S_OK],
2897+ cover=PJLINK_ERST_STATUS[E_WARN],
2898+ filt=PJLINK_ERST_STATUS[S_OK],
2899+ other=PJLINK_ERST_STATUS[S_OK])
2900+ chk_test = {'Cover': E_WARN}
2901+
2902 # GIVEN: Test object
2903- pjlink = pjlink_test
2904- chk_test = PJLINK_ERST_STATUS[E_WARN]
2905- chk_string = ERROR_STRING[E_WARN]
2906- pos = PJLINK_ERST_DATA['COVER']
2907- build_chk = []
2908- for check in range(0, len(PJLINK_ERST_POSITIONS)):
2909- if check == pos:
2910- build_chk.append(chk_test)
2911- else:
2912- build_chk.append(PJLINK_ERST_STATUS['OK'])
2913- chk_param = ''.join(build_chk)
2914-
2915- # WHEN: process_erst with cover only set to WARN and all others set to OK
2916- pjlink.process_erst(chk_param)
2917-
2918- # THEN: Only COVER should have an error
2919- self.assertEqual(len(pjlink.projector_errors), 1, 'projector_errors should only have 1 error')
2920- self.assertTrue(('Cover' in pjlink.projector_errors), 'projector_errors should have an error for "Cover"')
2921- self.assertEqual(pjlink.projector_errors['Cover'],
2922- chk_string,
2923- 'projector_errors["Cover"] should have error "{err}"'.format(err=chk_string))
2924-
2925- def test_projector_process_inpt(self):
2926+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2927+ pjlink.projector_errors = None
2928+
2929+ # WHEN: process_erst with status set to WARN
2930+ pjlink.process_erst(chk_data)
2931+
2932+ # THEN: PJLink instance errors should match only cover warning
2933+ assert 1 == len(pjlink.projector_errors), 'There should only be 1 error listed in projector_errors'
2934+ assert 'Cover' in pjlink.projector_errors, '"Cover" should be the only error listed'
2935+ assert pjlink.projector_errors['Cover'] == E_WARN, '"Cover" should have E_WARN listed as error'
2936+ assert chk_test == pjlink.projector_errors, 'projector_errors should match test errors'
2937+
2938+ def test_projector_process_inpt_valid(self):
2939 """
2940 Test input source status shows current input
2941 """
2942+ log_debug_calls = [call('(111.111.111.111) reset_information() connect status is S_NOT_CONNECTED')]
2943+ chk_source_available = ['11', '12', '21', '22', '31', '32']
2944+
2945 # GIVEN: Test object
2946- pjlink = pjlink_test
2947- pjlink.source = '0'
2948-
2949- # WHEN: Called with input source
2950- pjlink.process_inpt('1')
2951-
2952- # THEN: Input selected should reflect current input
2953- self.assertEqual(pjlink.source, '1', 'Input source should be set to "1"')
2954-
2955- @patch.object(pjlink_test, 'projectorUpdateIcons')
2956- @patch.object(openlp.core.projectors.pjlink, 'log')
2957- def test_projector_process_inst(self, mock_log, mock_UpdateIcons):
2958+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
2959+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
2960+ pjlink.source_available = chk_source_available
2961+ pjlink.source = '11'
2962+
2963+ # WHEN: Called with input source
2964+ pjlink.process_inpt('21')
2965+
2966+ # THEN: Input selected should reflect current input
2967+ assert pjlink.source == '21', 'Input source should be set to "21"'
2968+ mock_log.debug.assert_has_calls(log_debug_calls)
2969+
2970+ def test_projector_process_input_not_in_list(self):
2971+ """
2972+ Test setting input outside of available inputs
2973+
2974+ TODO: Future test
2975+ """
2976+ pass
2977+
2978+ def test_projector_process_input_not_in_default(self):
2979+ """
2980+ Test setting input with no sources available
2981+ TODO: Future test
2982+ """
2983+ pass
2984+
2985+ def test_projector_process_input_invalid(self):
2986+ """
2987+ Test setting input with an invalid value
2988+
2989+ TODO: Future test
2990+ """
2991+
2992+ def test_projector_process_inst_class_1(self):
2993 """
2994 Test saving video source available information
2995 """
2996+ log_debug_calls = [call('(111.111.111.111) Setting projector sources_available to '
2997+ '"[\'11\', \'12\', \'21\', \'22\', \'31\', \'32\']"')]
2998+ chk_data = '21 12 11 22 32 31' # Although they should already be sorted, use unsorted to verify method
2999+ chk_test = ['11', '12', '21', '22', '31', '32']
3000+
3001 # GIVEN: Test object
3002- pjlink = pjlink_test
3003- pjlink.source_available = []
3004- test_data = '21 10 30 31 11 20'
3005- test_saved = ["10", "11", "20", "21", "30", "31"]
3006- log_data = "(127.0.0.1) Setting projector sources_available to " \
3007- "\"['10', '11', '20', '21', '30', '31']\""
3008- mock_UpdateIcons.reset_mock()
3009- mock_log.reset_mock()
3010-
3011- # WHEN: process_inst called with test data
3012- pjlink.process_inst(data=test_data)
3013-
3014- # THEN: Data should have been sorted and saved properly
3015- self.assertEqual(pjlink.source_available, test_saved, "Sources should have been sorted and saved")
3016- mock_log.debug.assert_called_once_with(log_data)
3017- self.assertTrue(mock_UpdateIcons.emit.called, 'Update Icons should have been called')
3018-
3019- @patch.object(openlp.core.projectors.pjlink, 'log')
3020- def test_projector_process_lamp_invalid(self, mock_log):
3021+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3022+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3023+ pjlink.source_available = []
3024+
3025+ # WHEN: process_inst called with test data
3026+ pjlink.process_inst(data=chk_data)
3027+
3028+ # THEN: Data should have been sorted and saved properly
3029+ assert pjlink.source_available == chk_test, "Sources should have been sorted and saved"
3030+ mock_log.debug.assert_has_calls(log_debug_calls)
3031+
3032+ def test_projector_process_lamp_invalid(self):
3033 """
3034 Test status multiple lamp on/off and hours
3035 """
3036+ log_data = [call('(111.111.111.111) process_lamp(): Invalid data "11111 1 22222 0 333A3 1"')]
3037+
3038 # GIVEN: Test object
3039- pjlink = pjlink_test
3040- pjlink.lamp = [{'Hours': 00000, 'On': True},
3041- {'Hours': 11111, 'On': False}]
3042- log_data = '(127.0.0.1) process_lamp(): Invalid data "11111 1 22222 0 333A3 1"'
3043-
3044- # WHEN: Call process_command with invalid lamp data
3045- pjlink.process_lamp('11111 1 22222 0 333A3 1')
3046-
3047- # THEN: lamps should not have changed
3048- self.assertEqual(len(pjlink.lamp), 2,
3049- 'Projector should have kept 2 lamps specified')
3050- self.assertEqual(pjlink.lamp[0]['On'], True,
3051- 'Lamp 1 power status should have been set to TRUE')
3052- self.assertEqual(pjlink.lamp[0]['Hours'], 00000,
3053- 'Lamp 1 hours should have been left at 00000')
3054- self.assertEqual(pjlink.lamp[1]['On'], False,
3055- 'Lamp 2 power status should have been set to FALSE')
3056- self.assertEqual(pjlink.lamp[1]['Hours'], 11111,
3057- 'Lamp 2 hours should have been left at 11111')
3058- mock_log.warning.assert_called_once_with(log_data)
3059+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3060+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3061+ pjlink.lamp = [{'Hours': 00000, 'On': True},
3062+ {'Hours': 11111, 'On': False}]
3063+
3064+ # WHEN: Call process_command with invalid lamp data
3065+ pjlink.process_lamp('11111 1 22222 0 333A3 1')
3066+
3067+ # THEN: lamps should not have changed
3068+ assert 2 == len(pjlink.lamp), 'Projector should have kept 2 lamps specified'
3069+ assert pjlink.lamp[0]['On'] is True, 'Lamp 1 power status should have stayed TRUE'
3070+ assert 00000 == pjlink.lamp[0]['Hours'], 'Lamp 1 hours should have been left at 00000'
3071+ assert pjlink.lamp[1]['On'] is False, 'Lamp 2 power status should have stayed FALSE'
3072+ assert 11111 == pjlink.lamp[1]['Hours'], 'Lamp 2 hours should have been left at 11111'
3073+ mock_log.warning.assert_has_calls(log_data)
3074
3075 def test_projector_process_lamp_multiple(self):
3076 """
3077 Test status multiple lamp on/off and hours
3078 """
3079 # GIVEN: Test object
3080- pjlink = pjlink_test
3081- pjlink.lamps = []
3082+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3083+ pjlink.lamp = []
3084
3085- # WHEN: Call process_command with lamp data
3086+ # WHEN: Call process_command with invalid lamp data
3087 pjlink.process_lamp('11111 1 22222 0 33333 1')
3088
3089 # THEN: Lamp should have been set with proper lamp status
3090- self.assertEqual(len(pjlink.lamp), 3,
3091- 'Projector should have 3 lamps specified')
3092- self.assertEqual(pjlink.lamp[0]['On'], True,
3093- 'Lamp 1 power status should have been set to TRUE')
3094- self.assertEqual(pjlink.lamp[0]['Hours'], 11111,
3095- 'Lamp 1 hours should have been set to 11111')
3096- self.assertEqual(pjlink.lamp[1]['On'], False,
3097- 'Lamp 2 power status should have been set to FALSE')
3098- self.assertEqual(pjlink.lamp[1]['Hours'], 22222,
3099- 'Lamp 2 hours should have been set to 22222')
3100- self.assertEqual(pjlink.lamp[2]['On'], True,
3101- 'Lamp 3 power status should have been set to TRUE')
3102- self.assertEqual(pjlink.lamp[2]['Hours'], 33333,
3103- 'Lamp 3 hours should have been set to 33333')
3104+ assert 3 == len(pjlink.lamp), 'Projector should have 3 lamps specified'
3105+ assert pjlink.lamp[0]['On'] is True, 'Lamp 1 power status should have been set to TRUE'
3106+ assert 11111 == pjlink.lamp[0]['Hours'], 'Lamp 1 hours should have been set to 11111'
3107+ assert pjlink.lamp[1]['On'] is False, 'Lamp 2 power status should have been set to FALSE'
3108+ assert 22222 == pjlink.lamp[1]['Hours'], 'Lamp 2 hours should have been set to 22222'
3109+ assert pjlink.lamp[2]['On'] is True, 'Lamp 3 power status should have been set to TRUE'
3110+ assert 33333 == pjlink.lamp[2]['Hours'], 'Lamp 3 hours should have been set to 33333'
3111
3112 def test_projector_process_lamp_single(self):
3113 """
3114 Test status lamp on/off and hours
3115 """
3116+
3117 # GIVEN: Test object
3118- pjlink = pjlink_test
3119- pjlink.lamps = []
3120+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3121+ pjlink.lamp = []
3122
3123- # WHEN: Call process_command with lamp data
3124+ # WHEN: Call process_command with invalid lamp data
3125 pjlink.process_lamp('22222 1')
3126
3127 # THEN: Lamp should have been set with status=ON and hours=22222
3128- self.assertEqual(pjlink.lamp[0]['On'], True,
3129- 'Lamp power status should have been set to TRUE')
3130- self.assertEqual(pjlink.lamp[0]['Hours'], 22222,
3131- 'Lamp hours should have been set to 22222')
3132+ assert 1 == len(pjlink.lamp), 'Projector should have only 1 lamp'
3133+ assert pjlink.lamp[0]['On'] is True, 'Lamp power status should have been set to TRUE'
3134+ assert 22222 == pjlink.lamp[0]['Hours'], 'Lamp hours should have been set to 22222'
3135
3136- @patch.object(openlp.core.projectors.pjlink, 'log')
3137- def test_projector_process_name(self, mock_log):
3138+ def test_projector_process_name(self):
3139 """
3140 Test saving NAME data from projector
3141 """
3142- # GIVEN: Test data
3143- pjlink = pjlink_test
3144- test_data = "Some Name the End-User Set IN Projector"
3145- test_log = '(127.0.0.1) Setting projector PJLink name to "Some Name the End-User Set IN Projector"'
3146- mock_log.reset_mock()
3147-
3148- # WHEN: process_name called with test data
3149- pjlink.process_name(data=test_data)
3150-
3151- # THEN: name should be set and logged
3152- self.assertEqual(pjlink.pjlink_name, test_data, 'Name test data should have been saved')
3153- mock_log.debug.assert_called_once_with(test_log)
3154-
3155- @patch.object(pjlink_test, 'projectorUpdateIcons')
3156- @patch.object(pjlink_test, 'send_command')
3157- @patch.object(pjlink_test, 'change_status')
3158- def test_projector_process_powr_on(self,
3159- mock_change_status,
3160- mock_send_command,
3161- mock_UpdateIcons):
3162+ chk_data = "Some Name the End-User Set IN Projector"
3163+ log_debug_calls = [call('(111.111.111.111) Setting projector PJLink name to '
3164+ '"Some Name the End-User Set IN Projector"')]
3165+
3166+ # GIVEN: Test object
3167+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3168+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3169+
3170+ # WHEN: process_name called with test data
3171+ pjlink.process_name(data=chk_data)
3172+
3173+ # THEN: name should be set and logged
3174+ assert pjlink.pjlink_name == chk_data, 'Name test data should have been saved'
3175+ mock_log.debug.assert_has_calls(log_debug_calls)
3176+
3177+ def test_projector_process_powr_on(self):
3178 """
3179 Test status power to ON
3180 """
3181- # GIVEN: Test object and preset
3182- pjlink = pjlink_test
3183- pjlink.power = S_STANDBY
3184- test_data = PJLINK_POWR_STATUS[S_ON]
3185-
3186- # WHEN: Call process_command with turn power on command
3187- pjlink.process_command(cmd='POWR', data=test_data)
3188-
3189- # THEN: Power should be set to ON
3190- self.assertEqual(pjlink.power, S_ON, 'Power should have been set to ON')
3191- mock_send_command.assert_called_once_with('INST')
3192- mock_change_status.assert_called_once_with(PJLINK_POWR_STATUS[test_data])
3193- self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
3194-
3195- @patch.object(pjlink_test, 'projectorUpdateIcons')
3196- @patch.object(pjlink_test, 'send_command')
3197- @patch.object(pjlink_test, 'change_status')
3198- def test_projector_process_powr_invalid(self,
3199- mock_change_status,
3200- mock_send_command,
3201- mock_UpdateIcons):
3202+ # GIVEN: Test object
3203+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
3204+ patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
3205+ patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
3206+
3207+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3208+ pjlink.power = S_STANDBY
3209+
3210+ # WHEN: process_name called with test data
3211+ pjlink.process_powr(data=PJLINK_POWR_STATUS[S_ON])
3212+
3213+ # THEN: Power should be set to ON
3214+ assert pjlink.power == S_ON, 'Power should have been set to ON'
3215+ assert mock_UpdateIcons.emit.called is True, 'projectorUpdateIcons should have been called'
3216+ mock_send_command.assert_called_once_with('INST')
3217+ mock_change_status.assert_called_once_with(S_ON)
3218+
3219+ def test_projector_process_powr_invalid(self):
3220 """
3221 Test process_powr invalid call
3222 """
3223- # GIVEN: Test object and preset
3224- pjlink = pjlink_test
3225- pjlink.power = S_STANDBY
3226- test_data = '99'
3227-
3228- # WHEN: Call process_command with turn power on command
3229- pjlink.process_command(cmd='POWR', data=test_data)
3230-
3231- # THEN: Power should be set to ON
3232- self.assertEqual(pjlink.power, S_STANDBY, 'Power should not have changed')
3233- self.assertFalse(mock_change_status.called, 'Change status should not have been called')
3234- self.assertFalse(mock_send_command.called, 'send_command("INST") should not have been called')
3235- self.assertFalse(mock_UpdateIcons.emit.called, 'projectorUpdateIcons should not have been called')
3236-
3237- @patch.object(pjlink_test, 'projectorUpdateIcons')
3238- @patch.object(pjlink_test, 'send_command')
3239- @patch.object(pjlink_test, 'change_status')
3240- def test_projector_process_powr_off(self,
3241- mock_change_status,
3242- mock_send_command,
3243- mock_UpdateIcons):
3244+ log_warn_calls = [call('(111.111.111.111) Unknown power response: "99"')]
3245+
3246+ # GIVEN: Test object
3247+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
3248+ patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
3249+ patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
3250+ patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
3251+
3252+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3253+ pjlink.power = S_STANDBY
3254+
3255+ # WHEN: process_name called with test data
3256+ pjlink.process_powr(data='99')
3257+
3258+ # THEN: Power should be set to ON
3259+ assert pjlink.power == S_STANDBY, 'Power should not have changed'
3260+ assert mock_UpdateIcons.emit.called is False, 'projectorUpdateIcons() should not have been called'
3261+ mock_change_status.called is False, 'change_status() should not have been called'
3262+ mock_send_command.called is False, 'send_command() should not have been called'
3263+ mock_log.warning.assert_has_calls(log_warn_calls)
3264+
3265+ def test_projector_process_powr_off(self):
3266 """
3267 Test status power to STANDBY
3268 """
3269- # GIVEN: Test object and preset
3270- pjlink = pjlink_test
3271- pjlink.power = S_ON
3272- test_data = PJLINK_POWR_STATUS[S_STANDBY]
3273-
3274- # WHEN: Call process_command with turn power on command
3275- pjlink.process_command(cmd='POWR', data=test_data)
3276-
3277- # THEN: Power should be set to STANDBY
3278- self.assertEqual(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')
3279- self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
3280- mock_change_status.assert_called_once_with(PJLINK_POWR_STATUS[test_data])
3281- self.assertFalse(mock_send_command.called, "send_command['INST'] should not have been called")
3282+ # GIVEN: Test object
3283+ with patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
3284+ patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
3285+ patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
3286+
3287+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3288+ pjlink.power = S_ON
3289+
3290+ # WHEN: process_name called with test data
3291+ pjlink.process_powr(data=PJLINK_POWR_STATUS[S_STANDBY])
3292+
3293+ # THEN: Power should be set to ON
3294+ assert pjlink.power == S_STANDBY, 'Power should have changed to S_STANDBY'
3295+ assert mock_UpdateIcons.emit.called is True, 'projectorUpdateIcons should have been called'
3296+ mock_change_status.called is True, 'change_status should have been called'
3297+ mock_send_command.called is False, 'send_command should not have been called'
3298
3299 def test_projector_process_rfil_save(self):
3300 """
3301 Test saving filter type
3302 """
3303+ filter_model = 'Filter Type Test'
3304+
3305 # GIVEN: Test object
3306- pjlink = pjlink_test
3307+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3308 pjlink.model_filter = None
3309- filter_model = 'Filter Type Test'
3310
3311 # WHEN: Filter model is received
3312 pjlink.process_rfil(data=filter_model)
3313
3314 # THEN: Filter model number should be saved
3315- self.assertEqual(pjlink.model_filter, filter_model, 'Filter type should have been saved')
3316+ assert pjlink.model_filter == filter_model, 'Filter type should have been saved'
3317
3318 def test_projector_process_rfil_nosave(self):
3319 """
3320 Test saving filter type previously saved
3321 """
3322+ filter_model = 'Filter Type Test'
3323+ log_warn_calls = [call('(111.111.111.111) Filter model already set'),
3324+ call('(111.111.111.111) Saved model: "Old filter type"'),
3325+ call('(111.111.111.111) New model: "Filter Type Test"')]
3326+
3327 # GIVEN: Test object
3328- pjlink = pjlink_test
3329- pjlink.model_filter = 'Old filter type'
3330- filter_model = 'Filter Type Test'
3331-
3332- # WHEN: Filter model is received
3333- pjlink.process_rfil(data=filter_model)
3334-
3335- # THEN: Filter model number should be saved
3336- self.assertNotEquals(pjlink.model_filter, filter_model, 'Filter type should NOT have been saved')
3337+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3338+
3339+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3340+ pjlink.model_filter = 'Old filter type'
3341+
3342+ # WHEN: Filter model is received
3343+ pjlink.process_rfil(data=filter_model)
3344+
3345+ # THEN: Filter model number should be saved
3346+ assert pjlink.model_filter != filter_model, 'Filter type should NOT have been saved'
3347+ mock_log.warning.assert_has_calls(log_warn_calls)
3348
3349 def test_projector_process_rlmp_save(self):
3350 """
3351 Test saving lamp type
3352 """
3353 # GIVEN: Test object
3354- pjlink = pjlink_test
3355+ # GIVEN: Test object
3356+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3357 pjlink.model_lamp = None
3358 lamp_model = 'Lamp Type Test'
3359
3360@@ -961,159 +1041,179 @@
3361 pjlink.process_rlmp(data=lamp_model)
3362
3363 # THEN: Filter model number should be saved
3364- self.assertEqual(pjlink.model_lamp, lamp_model, 'Lamp type should have been saved')
3365+ assert pjlink.model_lamp == lamp_model, 'Lamp type should have been saved'
3366
3367 def test_projector_process_rlmp_nosave(self):
3368 """
3369 Test saving lamp type previously saved
3370 """
3371+ lamp_model = 'Lamp Type Test'
3372+ log_warn_calls = [call('(111.111.111.111) Lamp model already set'),
3373+ call('(111.111.111.111) Saved lamp: "Old lamp type"'),
3374+ call('(111.111.111.111) New lamp: "Lamp Type Test"')]
3375+
3376 # GIVEN: Test object
3377- pjlink = pjlink_test
3378- pjlink.model_lamp = 'Old lamp type'
3379- lamp_model = 'Filter Type Test'
3380-
3381- # WHEN: Filter model is received
3382- pjlink.process_rlmp(data=lamp_model)
3383-
3384- # THEN: Filter model number should be saved
3385- self.assertNotEquals(pjlink.model_lamp, lamp_model, 'Lamp type should NOT have been saved')
3386+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3387+
3388+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3389+ pjlink.model_lamp = 'Old lamp type'
3390+
3391+ # WHEN: Filter model is received
3392+ pjlink.process_rlmp(data=lamp_model)
3393+
3394+ # THEN: Filter model number should be saved
3395+ assert pjlink.model_lamp != lamp_model, 'Lamp type should NOT have been saved'
3396+ mock_log.warning.assert_has_calls(log_warn_calls)
3397
3398 def test_projector_process_snum_set(self):
3399 """
3400 Test saving serial number from projector
3401 """
3402+ log_debug_calls = [call('(111.111.111.111) Setting projector serial number to "Test Serial Number"')]
3403+ test_number = 'Test Serial Number'
3404+
3405 # GIVEN: Test object
3406- pjlink = pjlink_test
3407- pjlink.serial_no = None
3408- test_number = 'Test Serial Number'
3409-
3410- # WHEN: No serial number is set and we receive serial number command
3411- pjlink.process_snum(data=test_number)
3412-
3413- # THEN: Serial number should be set
3414- self.assertEqual(pjlink.serial_no, test_number,
3415- 'Projector serial number should have been set')
3416+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3417+
3418+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3419+ pjlink.serial_no = None
3420+
3421+ # WHEN: No serial number is set and we receive serial number command
3422+ pjlink.process_snum(data=test_number)
3423+
3424+ # THEN: Serial number should be set
3425+ assert pjlink.serial_no == test_number, 'Projector serial number should have been set'
3426+ mock_log.debug.assert_has_calls(log_debug_calls)
3427
3428 def test_projector_process_snum_different(self):
3429 """
3430 Test projector serial number different than saved serial number
3431 """
3432- # GIVEN: Test object
3433- pjlink = pjlink_test
3434- pjlink.serial_no = 'Previous serial number'
3435+ log_warn_calls = [call('(111.111.111.111) Projector serial number does not match saved serial number'),
3436+ call('(111.111.111.111) Saved: "Previous serial number"'),
3437+ call('(111.111.111.111) Received: "Test Serial Number"'),
3438+ call('(111.111.111.111) NOT saving serial number')]
3439 test_number = 'Test Serial Number'
3440
3441- # WHEN: No serial number is set and we receive serial number command
3442- pjlink.process_snum(data=test_number)
3443-
3444- # THEN: Serial number should be set
3445- self.assertNotEquals(pjlink.serial_no, test_number,
3446- 'Projector serial number should NOT have been set')
3447-
3448- @patch.object(openlp.core.projectors.pjlink, 'log')
3449- def test_projector_process_sver(self, mock_log):
3450+ # GIVEN: Test object
3451+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3452+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3453+ pjlink.serial_no = 'Previous serial number'
3454+
3455+ # WHEN: No serial number is set and we receive serial number command
3456+ pjlink.process_snum(data=test_number)
3457+
3458+ # THEN: Serial number should be set
3459+ assert pjlink.serial_no != test_number, 'Projector serial number should NOT have been set'
3460+ mock_log.warning.assert_has_calls(log_warn_calls)
3461+
3462+ def test_projector_process_sver(self):
3463 """
3464 Test invalid software version information - too long
3465 """
3466- # GIVEN: Test object
3467- pjlink = pjlink_test
3468- pjlink.sw_version = None
3469- pjlink.sw_version_received = None
3470 test_data = 'Test 1 Subtest 1'
3471- test_log = '(127.0.0.1) Setting projector software version to "Test 1 Subtest 1"'
3472- mock_log.reset_mock()
3473-
3474- # WHEN: process_sver called with invalid data
3475- pjlink.process_sver(data=test_data)
3476-
3477- # THEN: Version information should not change
3478- self.assertEqual(pjlink.sw_version, test_data, 'Software version should have been updated')
3479- self.assertIsNone(pjlink.sw_version_received, 'Received software version should not have changed')
3480- mock_log.debug.assert_called_once_with(test_log)
3481-
3482- @patch.object(openlp.core.projectors.pjlink, 'log')
3483- def test_projector_process_sver_changed(self, mock_log):
3484+ log_debug_calls = [call('(111.111.111.111) Setting projector software version to "Test 1 Subtest 1"')]
3485+
3486+ # GIVEN: Test object
3487+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3488+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3489+ pjlink.sw_version = None
3490+ pjlink.sw_version_received = None
3491+
3492+ # WHEN: process_sver called with invalid data
3493+ pjlink.process_sver(data=test_data)
3494+
3495+ # THEN: Version information should not change
3496+ assert pjlink.sw_version == test_data, 'Software version should have been updated'
3497+ mock_log.debug.assert_has_calls(log_debug_calls)
3498+
3499+ def test_projector_process_sver_changed(self):
3500 """
3501 Test invalid software version information - Received different than saved
3502 """
3503- # GIVEN: Test object
3504- pjlink = pjlink_test
3505+ test_data_old = 'Test 1 Subtest 1'
3506 test_data_new = 'Test 1 Subtest 2'
3507- test_data_old = 'Test 1 Subtest 1'
3508- pjlink.sw_version = test_data_old
3509- pjlink.sw_version_received = None
3510- test_log = '(127.0.0.1) Saving new serial number as sw_version_received'
3511- mock_log.reset_mock()
3512-
3513- # WHEN: process_sver called with invalid data
3514- pjlink.process_sver(data=test_data_new)
3515-
3516- # THEN: Version information should not change
3517- self.assertEqual(pjlink.sw_version, test_data_old, 'Software version should not have been updated')
3518- self.assertEqual(pjlink.sw_version_received, test_data_new,
3519- 'Received software version should have been changed')
3520- self.assertEqual(mock_log.warning.call_count, 4, 'log.warn should have been called 4 times')
3521- # There was 4 calls, but only the last one is checked with this method
3522- mock_log.warning.assert_called_with(test_log)
3523-
3524- @patch.object(openlp.core.projectors.pjlink, 'log')
3525- def test_projector_process_sver_invalid(self, mock_log):
3526+ log_warn_calls = [call('(111.111.111.111) Projector software version does not match saved software version'),
3527+ call('(111.111.111.111) Saved: "Test 1 Subtest 1"'),
3528+ call('(111.111.111.111) Received: "Test 1 Subtest 2"'),
3529+ call('(111.111.111.111) Updating software version')]
3530+
3531+ # GIVEN: Test object
3532+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3533+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3534+ pjlink.sw_version = test_data_old
3535+
3536+ # WHEN: process_sver called with invalid data
3537+ pjlink.process_sver(data=test_data_new)
3538+
3539+ # THEN: Version information should not change
3540+ assert pjlink.sw_version == test_data_new, 'Software version should have changed'
3541+ mock_log.warning.assert_has_calls(log_warn_calls)
3542+
3543+ def test_projector_process_sver_invalid(self):
3544 """
3545 Test invalid software version information - too long
3546 """
3547- # GIVEN: Test object
3548- pjlink = pjlink_test
3549- pjlink.sw_version = None
3550- pjlink.sw_version_received = None
3551 test_data = 'This is a test software version line that is too long based on PJLink version 2 specs'
3552- test_log = "Invalid software version - too long"
3553- mock_log.reset_mock()
3554-
3555- # WHEN: process_sver called with invalid data
3556- pjlink.process_sver(data=test_data)
3557-
3558- # THEN: Version information should not change
3559- self.assertIsNone(pjlink.sw_version, 'Software version should not have changed')
3560- self.assertIsNone(pjlink.sw_version_received, 'Received software version should not have changed')
3561- mock_log.warning.assert_called_once_with(test_log)
3562+ log_warn_calls = [call('Invalid software version - too long')]
3563+
3564+ # GIVEN: Test object
3565+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3566+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3567+ pjlink.sw_version = None
3568+
3569+ # WHEN: process_sver called with invalid data
3570+ pjlink.process_sver(data=test_data)
3571+
3572+ # THEN: Version information should not change
3573+ assert pjlink.sw_version is None, 'Software version should not have changed'
3574+ assert pjlink.sw_version_received is None, 'Received software version should not have changed'
3575+ mock_log.warning.assert_has_calls(log_warn_calls)
3576
3577 def test_projector_reset_information(self):
3578 """
3579 Test reset_information() resets all information and stops timers
3580 """
3581- # GIVEN: Test object and test data
3582- pjlink = pjlink_test
3583- pjlink.power = S_ON
3584- pjlink.pjlink_name = 'OPENLPTEST'
3585- pjlink.manufacturer = 'PJLINK'
3586- pjlink.model = '1'
3587- pjlink.shutter = True
3588- pjlink.mute = True
3589- pjlink.lamp = True
3590- pjlink.fan = True
3591- pjlink.source_available = True
3592- pjlink.other_info = 'ANOTHER TEST'
3593- pjlink.send_queue = True
3594- pjlink.send_busy = True
3595-
3596- # WHEN: reset_information() is called
3597- with patch.object(pjlink, 'timer') as mock_timer:
3598- with patch.object(pjlink, 'socket_timer') as mock_socket_timer:
3599+ log_debug_calls = [call('(111.111.111.111): Calling timer.stop()'),
3600+ call('(111.111.111.111): Calling socket_timer.stop()')]
3601+
3602+ # GIVEN: Test object
3603+ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
3604+ pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
3605+ # timer and socket_timer not available until instantiation, so mock here
3606+ with patch.object(pjlink, 'socket_timer') as mock_socket_timer, \
3607+ patch.object(pjlink, 'timer') as mock_timer:
3608+
3609+ pjlink.power = S_ON
3610+ pjlink.pjlink_name = 'OPENLPTEST'
3611+ pjlink.manufacturer = 'PJLINK'
3612+ pjlink.model = '1'
3613+ pjlink.shutter = True
3614+ pjlink.mute = True
3615+ pjlink.lamp = True
3616+ pjlink.fan = True
3617+ pjlink.source_available = True
3618+ pjlink.other_info = 'ANOTHER TEST'
3619+ pjlink.send_queue = True
3620+ pjlink.send_busy = True
3621+
3622+ # WHEN: reset_information() is called
3623 pjlink.reset_information()
3624
3625- # THEN: All information should be reset and timers stopped
3626- self.assertEqual(pjlink.power, S_OFF, 'Projector power should be OFF')
3627- self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None')
3628- self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None')
3629- self.assertIsNone(pjlink.model, 'Projector model should be None')
3630- self.assertIsNone(pjlink.shutter, 'Projector shutter should be None')
3631- self.assertIsNone(pjlink.mute, 'Projector shuttter should be None')
3632- self.assertIsNone(pjlink.lamp, 'Projector lamp should be None')
3633- self.assertIsNone(pjlink.fan, 'Projector fan should be None')
3634- self.assertIsNone(pjlink.source_available, 'Projector source_available should be None')
3635- self.assertIsNone(pjlink.source, 'Projector source should be None')
3636- self.assertIsNone(pjlink.other_info, 'Projector other_info should be None')
3637- self.assertEqual(pjlink.send_queue, [], 'Projector send_queue should be an empty list')
3638- self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
3639- self.assertTrue(mock_timer.stop.called, 'Projector timer.stop() should have been called')
3640- self.assertTrue(mock_socket_timer.stop.called, 'Projector socket_timer.stop() should have been called')
3641+ # THEN: All information should be reset and timers stopped
3642+ assert pjlink.power == S_OFF, 'Projector power should be OFF'
3643+ assert pjlink.pjlink_name is None, 'Projector pjlink_name should be None'
3644+ assert pjlink.manufacturer is None, 'Projector manufacturer should be None'
3645+ assert pjlink.model is None, 'Projector model should be None'
3646+ assert pjlink.shutter is None, 'Projector shutter should be None'
3647+ assert pjlink.mute is None, 'Projector shuttter should be None'
3648+ assert pjlink.lamp is None, 'Projector lamp should be None'
3649+ assert pjlink.fan is None, 'Projector fan should be None'
3650+ assert pjlink.source_available is None, 'Projector source_available should be None'
3651+ assert pjlink.source is None, 'Projector source should be None'
3652+ assert pjlink.other_info is None, 'Projector other_info should be None'
3653+ assert pjlink.send_queue == [], 'Projector send_queue should be an empty list'
3654+ assert pjlink.send_busy is False, 'Projector send_busy should be False'
3655+ assert mock_timer.stop.called is True, 'Projector timer.stop() should have been called'
3656+ assert mock_socket_timer.stop.called is True, 'Projector socket_timer.stop() should have been called'
3657+ mock_log.debug.assert_has_calls(log_debug_calls)