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
=== modified file 'openlp/core/projectors/constants.py'
--- openlp/core/projectors/constants.py 2017-12-29 09:15:48 +0000
+++ openlp/core/projectors/constants.py 2018-01-03 05:54:24 +0000
@@ -32,9 +32,128 @@
32# Set common constants.32# Set common constants.
33CR = chr(0x0D) # \r33CR = chr(0x0D) # \r
34LF = chr(0x0A) # \n34LF = chr(0x0A) # \n
35PJLINK_CLASS = '1' # Default to class 1 until we query the projector
36PJLINK_MAX_PACKET = 136
37PJLINK_PREFIX = '%'
35PJLINK_PORT = 435238PJLINK_PORT = 4352
36TIMEOUT = 30.039PJLINK_SUFFIX = CR
37PJLINK_MAX_PACKET = 13640PJLINK_TIMEOUT = 30.0
41
42# Error and status codes
43S_OK = E_OK = 0 # E_OK included since I sometimes forget
44
45# Error codes. Start at 200 so we don't duplicate system error codes.
46E_GENERAL = 200 # Unknown error
47E_NOT_CONNECTED = 201
48E_UNDEFINED = 202 # PJLink ERR1
49E_PARAMETER = 203 # PJLink ERR2
50E_UNAVAILABLE = 204 # PJLink ERR3
51E_PROJECTOR = 205 # PJLink ERR4
52E_AUTHENTICATION = 206 # PJLink ERRA
53E_NO_AUTHENTICATION = 207 # PJLink authentication mismatch between projector and program
54E_PREFIX = 208 # PJLink invalid prefix for packet
55E_CLASS = 209 # PJLink class version mismatch
56E_INVALID_DATA = 210
57E_WARN = 211
58E_ERROR = 212
59E_FAN = 213
60E_LAMP = 214
61E_TEMP = 215
62E_COVER = 216
63E_FILTER = 217
64E_UNKNOWN = 218
65
66# Remap Qt socket error codes to local error codes
67E_CONNECTION_REFUSED = 230
68E_REMOTE_HOST_CLOSED_CONNECTION = 231
69E_HOST_NOT_FOUND = 232
70E_SOCKET_ACCESS = 233
71E_SOCKET_RESOURCE = 234
72E_SOCKET_TIMEOUT = 235
73E_DATAGRAM_TOO_LARGE = 236
74E_NETWORK = 237
75E_ADDRESS_IN_USE = 238
76E_SOCKET_ADDRESS_NOT_AVAILABLE = 239
77E_UNSUPPORTED_SOCKET_OPERATION = 240
78E_PROXY_AUTHENTICATION_REQUIRED = 241
79E_SLS_HANDSHAKE_FAILED = 242
80E_UNFINISHED_SOCKET_OPERATION = 243
81E_PROXY_CONNECTION_REFUSED = 244
82E_PROXY_CONNECTION_CLOSED = 245
83E_PROXY_CONNECTION_TIMEOUT = 246
84E_PROXY_NOT_FOUND = 247
85E_PROXY_PROTOCOL = 248
86E_UNKNOWN_SOCKET_ERROR = 249
87
88# Status codes start at 300
89
90# Remap Qt socket states to local status codes
91S_NOT_CONNECTED = 300
92S_HOST_LOOKUP = 301
93S_CONNECTING = 302
94S_CONNECTED = 303
95S_BOUND = 304
96S_LISTENING = 305 # Listed as internal use only in QAbstractSocket
97S_CLOSING = 306
98
99# Projector states
100S_INITIALIZE = 310
101S_STATUS = 311
102S_OFF = 312
103S_STANDBY = 313
104S_WARMUP = 314
105S_ON = 315
106S_COOLDOWN = 316
107S_INFO = 317
108
109# Information that does not affect status
110S_NETWORK_IDLE = 400
111S_NETWORK_SENDING = 401
112S_NETWORK_RECEIVING = 402
113
114# Map PJlink errors to local status
115PJLINK_ERRORS = {
116 'ERRA': E_AUTHENTICATION, # Authentication error
117 'ERR1': E_UNDEFINED, # Undefined command error
118 'ERR2': E_PARAMETER, # Invalid parameter error
119 'ERR3': E_UNAVAILABLE, # Projector busy
120 'ERR4': E_PROJECTOR, # Projector or display failure
121 E_AUTHENTICATION: 'ERRA',
122 E_UNDEFINED: 'ERR1',
123 E_PARAMETER: 'ERR2',
124 E_UNAVAILABLE: 'ERR3',
125 E_PROJECTOR: 'ERR4'
126}
127
128# Map QAbstractSocketState enums to local status
129QSOCKET_STATE = {
130 0: S_NOT_CONNECTED, # 'UnconnectedState',
131 1: S_HOST_LOOKUP, # 'HostLookupState',
132 2: S_CONNECTING, # 'ConnectingState',
133 3: S_CONNECTED, # 'ConnectedState',
134 4: S_BOUND, # 'BoundState',
135 5: S_LISTENING, # 'ListeningState' - Noted as "Internal Use Only" on Qt website
136 6: S_CLOSING, # 'ClosingState',
137 S_NOT_CONNECTED: 0,
138 S_HOST_LOOKUP: 1,
139 S_CONNECTING: 2,
140 S_CONNECTED: 3,
141 S_BOUND: 4,
142 S_LISTENING: 5,
143 S_CLOSING: 6
144}
145
146PROJECTOR_STATE = [
147 S_INITIALIZE,
148 S_STATUS,
149 S_OFF,
150 S_STANDBY,
151 S_WARMUP,
152 S_ON,
153 S_COOLDOWN,
154 S_INFO
155]
156
38# NOTE: Changed format to account for some commands are both class 1 and 2157# NOTE: Changed format to account for some commands are both class 1 and 2
39PJLINK_VALID_CMD = {158PJLINK_VALID_CMD = {
40 'ACKN': {'version': ['2', ],159 'ACKN': {'version': ['2', ],
@@ -144,227 +263,140 @@
144 }263 }
145}264}
146265
147# QAbstractSocketState enums converted to string266CONNECTION_ERRORS = [
148S_QSOCKET_STATE = {267 E_ADDRESS_IN_USE,
149 0: 'QSocketState - UnconnectedState',268 E_CONNECTION_REFUSED,
150 1: 'QSocketState - HostLookupState',269 E_DATAGRAM_TOO_LARGE,
151 2: 'QSocketState - ConnectingState',270 E_HOST_NOT_FOUND,
152 3: 'QSocketState - ConnectedState',271 E_NETWORK,
153 4: 'QSocketState - BoundState',272 E_NOT_CONNECTED,
154 5: 'QSocketState - ListeningState (internal use only)',273 E_PROXY_AUTHENTICATION_REQUIRED,
155 6: 'QSocketState - ClosingState',274 E_PROXY_CONNECTION_CLOSED,
156 'UnconnectedState': 0,275 E_PROXY_CONNECTION_REFUSED,
157 'HostLookupState': 1,276 E_PROXY_CONNECTION_TIMEOUT,
158 'ConnectingState': 2,277 E_PROXY_NOT_FOUND,
159 'ConnectedState': 3,278 E_PROXY_PROTOCOL,
160 'BoundState': 4,279 E_REMOTE_HOST_CLOSED_CONNECTION,
161 'ListeningState': 5,280 E_SLS_HANDSHAKE_FAILED,
162 'ClosingState': 6281 E_SOCKET_ACCESS,
163}282 E_SOCKET_ADDRESS_NOT_AVAILABLE,
164283 E_SOCKET_RESOURCE,
165# Error and status codes284 E_SOCKET_TIMEOUT,
166S_OK = E_OK = 0 # E_OK included since I sometimes forget285 E_UNFINISHED_SOCKET_OPERATION,
167# Error codes. Start at 200 so we don't duplicate system error codes.286 E_UNKNOWN_SOCKET_ERROR,
168E_GENERAL = 200 # Unknown error287 E_UNSUPPORTED_SOCKET_OPERATION
169E_NOT_CONNECTED = 201288]
170E_FAN = 202289
171E_LAMP = 203290PROJECTOR_ERRORS = [
172E_TEMP = 204291 E_AUTHENTICATION,
173E_COVER = 205292 E_CLASS,
174E_FILTER = 206293 E_INVALID_DATA,
175E_NO_AUTHENTICATION = 207 # PIN set and no authentication set on projector294 E_NO_AUTHENTICATION,
176E_UNDEFINED = 208 # ERR1295 E_PARAMETER,
177E_PARAMETER = 209 # ERR2296 E_PREFIX,
178E_UNAVAILABLE = 210 # ERR3297 E_PROJECTOR,
179E_PROJECTOR = 211 # ERR4298 E_UNAVAILABLE,
180E_INVALID_DATA = 212299 E_UNDEFINED,
181E_WARN = 213300 E_UNKNOWN
182E_ERROR = 214301]
183E_AUTHENTICATION = 215 # ERRA302
184E_CLASS = 216303# Show status code as string
185E_PREFIX = 217304STATUS_CODE = {
186305 E_ADDRESS_IN_USE: 'E_ADDRESS_IN_USE',
187# Remap Qt socket error codes to projector error codes306 E_AUTHENTICATION: 'E_AUTHENTICATION',
188E_CONNECTION_REFUSED = 230307 E_CLASS: 'E_CLASS',
189E_REMOTE_HOST_CLOSED_CONNECTION = 231308 E_CONNECTION_REFUSED: 'E_CONNECTION_REFUSED',
190E_HOST_NOT_FOUND = 232309 E_COVER: 'E_COVER',
191E_SOCKET_ACCESS = 233310 E_DATAGRAM_TOO_LARGE: 'E_DATAGRAM_TOO_LARGE',
192E_SOCKET_RESOURCE = 234311 E_ERROR: 'E_ERROR',
193E_SOCKET_TIMEOUT = 235312 E_FAN: 'E_FAN',
194E_DATAGRAM_TOO_LARGE = 236313 E_FILTER: 'E_FILTER',
195E_NETWORK = 237
196E_ADDRESS_IN_USE = 238
197E_SOCKET_ADDRESS_NOT_AVAILABLE = 239
198E_UNSUPPORTED_SOCKET_OPERATION = 240
199E_PROXY_AUTHENTICATION_REQUIRED = 241
200E_SLS_HANDSHAKE_FAILED = 242
201E_UNFINISHED_SOCKET_OPERATION = 243
202E_PROXY_CONNECTION_REFUSED = 244
203E_PROXY_CONNECTION_CLOSED = 245
204E_PROXY_CONNECTION_TIMEOUT = 246
205E_PROXY_NOT_FOUND = 247
206E_PROXY_PROTOCOL = 248
207E_UNKNOWN_SOCKET_ERROR = -1
208
209# Status codes start at 300
210S_NOT_CONNECTED = 300
211S_CONNECTING = 301
212S_CONNECTED = 302
213S_INITIALIZE = 303
214S_STATUS = 304
215S_OFF = 305
216S_STANDBY = 306
217S_WARMUP = 307
218S_ON = 308
219S_COOLDOWN = 309
220S_INFO = 310
221
222# Information that does not affect status
223S_NETWORK_SENDING = 400
224S_NETWORK_RECEIVED = 401
225
226CONNECTION_ERRORS = {
227 E_NOT_CONNECTED, E_NO_AUTHENTICATION, E_AUTHENTICATION, E_CLASS,
228 E_PREFIX, E_CONNECTION_REFUSED, E_REMOTE_HOST_CLOSED_CONNECTION,
229 E_HOST_NOT_FOUND, E_SOCKET_ACCESS, E_SOCKET_RESOURCE, E_SOCKET_TIMEOUT,
230 E_DATAGRAM_TOO_LARGE, E_NETWORK, E_ADDRESS_IN_USE, E_SOCKET_ADDRESS_NOT_AVAILABLE,
231 E_UNSUPPORTED_SOCKET_OPERATION, E_PROXY_AUTHENTICATION_REQUIRED,
232 E_SLS_HANDSHAKE_FAILED, E_UNFINISHED_SOCKET_OPERATION, E_PROXY_CONNECTION_REFUSED,
233 E_PROXY_CONNECTION_CLOSED, E_PROXY_CONNECTION_TIMEOUT, E_PROXY_NOT_FOUND,
234 E_PROXY_PROTOCOL, E_UNKNOWN_SOCKET_ERROR
235}
236
237PJLINK_ERRORS = {
238 'ERRA': E_AUTHENTICATION, # Authentication error
239 'ERR1': E_UNDEFINED, # Undefined command error
240 'ERR2': E_PARAMETER, # Invalid parameter error
241 'ERR3': E_UNAVAILABLE, # Projector busy
242 'ERR4': E_PROJECTOR, # Projector or display failure
243 E_AUTHENTICATION: 'ERRA',
244 E_UNDEFINED: 'ERR1',
245 E_PARAMETER: 'ERR2',
246 E_UNAVAILABLE: 'ERR3',
247 E_PROJECTOR: 'ERR4'
248}
249
250# Map error/status codes to string
251ERROR_STRING = {
252 0: 'S_OK',
253 E_GENERAL: 'E_GENERAL',314 E_GENERAL: 'E_GENERAL',
254 E_NOT_CONNECTED: 'E_NOT_CONNECTED',315 E_HOST_NOT_FOUND: 'E_HOST_NOT_FOUND',
255 E_FAN: 'E_FAN',316 E_INVALID_DATA: 'E_INVALID_DATA',
256 E_LAMP: 'E_LAMP',317 E_LAMP: 'E_LAMP',
257 E_TEMP: 'E_TEMP',318 E_NETWORK: 'E_NETWORK',
258 E_COVER: 'E_COVER',
259 E_FILTER: 'E_FILTER',
260 E_AUTHENTICATION: 'E_AUTHENTICATION',
261 E_NO_AUTHENTICATION: 'E_NO_AUTHENTICATION',319 E_NO_AUTHENTICATION: 'E_NO_AUTHENTICATION',
262 E_UNDEFINED: 'E_UNDEFINED',320 E_NOT_CONNECTED: 'E_NOT_CONNECTED',
263 E_PARAMETER: 'E_PARAMETER',321 E_PARAMETER: 'E_PARAMETER',
264 E_UNAVAILABLE: 'E_UNAVAILABLE',322 E_PREFIX: 'E_PREFIX',
265 E_PROJECTOR: 'E_PROJECTOR',323 E_PROJECTOR: 'E_PROJECTOR',
266 E_INVALID_DATA: 'E_INVALID_DATA',324 E_PROXY_AUTHENTICATION_REQUIRED: 'E_PROXY_AUTHENTICATION_REQUIRED',
267 E_WARN: 'E_WARN',325 E_PROXY_CONNECTION_CLOSED: 'E_PROXY_CONNECTION_CLOSED',
268 E_ERROR: 'E_ERROR',326 E_PROXY_CONNECTION_REFUSED: 'E_PROXY_CONNECTION_REFUSED',
269 E_CLASS: 'E_CLASS',327 E_PROXY_CONNECTION_TIMEOUT: 'E_PROXY_CONNECTION_TIMEOUT',
270 E_PREFIX: 'E_PREFIX', # Last projector error328 E_PROXY_NOT_FOUND: 'E_PROXY_NOT_FOUND',
271 E_CONNECTION_REFUSED: 'E_CONNECTION_REFUSED', # First QtSocket error329 E_PROXY_PROTOCOL: 'E_PROXY_PROTOCOL',
272 E_REMOTE_HOST_CLOSED_CONNECTION: 'E_REMOTE_HOST_CLOSED_CONNECTION',330 E_REMOTE_HOST_CLOSED_CONNECTION: 'E_REMOTE_HOST_CLOSED_CONNECTION',
273 E_HOST_NOT_FOUND: 'E_HOST_NOT_FOUND',331 E_SLS_HANDSHAKE_FAILED: 'E_SLS_HANDSHAKE_FAILED',
274 E_SOCKET_ACCESS: 'E_SOCKET_ACCESS',332 E_SOCKET_ACCESS: 'E_SOCKET_ACCESS',
333 E_SOCKET_ADDRESS_NOT_AVAILABLE: 'E_SOCKET_ADDRESS_NOT_AVAILABLE',
275 E_SOCKET_RESOURCE: 'E_SOCKET_RESOURCE',334 E_SOCKET_RESOURCE: 'E_SOCKET_RESOURCE',
276 E_SOCKET_TIMEOUT: 'E_SOCKET_TIMEOUT',335 E_SOCKET_TIMEOUT: 'E_SOCKET_TIMEOUT',
277 E_DATAGRAM_TOO_LARGE: 'E_DATAGRAM_TOO_LARGE',336 E_TEMP: 'E_TEMP',
278 E_NETWORK: 'E_NETWORK',337 E_UNAVAILABLE: 'E_UNAVAILABLE',
279 E_ADDRESS_IN_USE: 'E_ADDRESS_IN_USE',338 E_UNDEFINED: 'E_UNDEFINED',
280 E_SOCKET_ADDRESS_NOT_AVAILABLE: 'E_SOCKET_ADDRESS_NOT_AVAILABLE',339 E_UNFINISHED_SOCKET_OPERATION: 'E_UNFINISHED_SOCKET_OPERATION',
340 E_UNKNOWN: 'E_UNKNOWN',
341 E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR',
281 E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION',342 E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION',
282 E_PROXY_AUTHENTICATION_REQUIRED: 'E_PROXY_AUTHENTICATION_REQUIRED',343 E_WARN: 'E_WARN',
283 E_SLS_HANDSHAKE_FAILED: 'E_SLS_HANDSHAKE_FAILED',344 S_BOUND: 'S_BOUND',
284 E_UNFINISHED_SOCKET_OPERATION: 'E_UNFINISHED_SOCKET_OPERATION',345 S_COOLDOWN: 'S_COOLDOWN',
285 E_PROXY_CONNECTION_REFUSED: 'E_PROXY_CONNECTION_REFUSED',346 S_CLOSING: 'S_CLOSING',
286 E_PROXY_CONNECTION_CLOSED: 'E_PROXY_CONNECTION_CLOSED',347 S_CONNECTED: 'S_CONNECTED',
287 E_PROXY_CONNECTION_TIMEOUT: 'E_PROXY_CONNECTION_TIMEOUT',348 S_CONNECTING: 'S_CONNECTING',
288 E_PROXY_NOT_FOUND: 'E_PROXY_NOT_FOUND',349 S_HOST_LOOKUP: 'S_HOST_LOOKUP',
289 E_PROXY_PROTOCOL: 'E_PROXY_PROTOCOL',350 S_INFO: 'S_INFO',
290 E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR'351 S_INITIALIZE: 'S_INITIALIZE',
291}352 S_LISTENING: 'S_LISTENING',
292353 S_NETWORK_RECEIVING: 'S_NETWORK_RECEIVING',
293STATUS_STRING = {354 S_NETWORK_SENDING: 'S_NETWORK_SENDING',
355 S_NETWORK_IDLE: 'S_NETWORK_IDLE',
294 S_NOT_CONNECTED: 'S_NOT_CONNECTED',356 S_NOT_CONNECTED: 'S_NOT_CONNECTED',
295 S_CONNECTING: 'S_CONNECTING',
296 S_CONNECTED: 'S_CONNECTED',
297 S_STATUS: 'S_STATUS',
298 S_OFF: 'S_OFF',357 S_OFF: 'S_OFF',
299 S_INITIALIZE: 'S_INITIALIZE',358 S_OK: 'S_OK', # S_OK or E_OK
359 S_ON: 'S_ON',
300 S_STANDBY: 'S_STANDBY',360 S_STANDBY: 'S_STANDBY',
361 S_STATUS: 'S_STATUS',
301 S_WARMUP: 'S_WARMUP',362 S_WARMUP: 'S_WARMUP',
302 S_ON: 'S_ON',
303 S_COOLDOWN: 'S_COOLDOWN',
304 S_INFO: 'S_INFO',
305 S_NETWORK_SENDING: 'S_NETWORK_SENDING',
306 S_NETWORK_RECEIVED: 'S_NETWORK_RECEIVED'
307}363}
308364
309# Map error/status codes to message strings365# Map status codes to message strings
310ERROR_MSG = {366STATUS_MSG = {
311 E_OK: translate('OpenLP.ProjectorConstants', 'OK'), # E_OK | S_OK367 E_ADDRESS_IN_USE: translate('OpenLP.ProjectorConstants',
312 E_GENERAL: translate('OpenLP.ProjectorConstants', 'General projector error'),368 'The address specified with socket.bind() '
313 E_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not connected error'),369 'is already in use and was set to be exclusive'),
314 E_LAMP: translate('OpenLP.ProjectorConstants', 'Lamp error'),370 E_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERRA: Authentication Error"'),
315 E_FAN: translate('OpenLP.ProjectorConstants', 'Fan error'),
316 E_TEMP: translate('OpenLP.ProjectorConstants', 'High temperature detected'),
317 E_COVER: translate('OpenLP.ProjectorConstants', 'Cover open detected'),
318 E_FILTER: translate('OpenLP.ProjectorConstants', 'Check filter'),
319 E_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'Authentication Error'),
320 E_UNDEFINED: translate('OpenLP.ProjectorConstants', 'Undefined Command'),
321 E_PARAMETER: translate('OpenLP.ProjectorConstants', 'Invalid Parameter'),
322 E_UNAVAILABLE: translate('OpenLP.ProjectorConstants', 'Projector Busy'),
323 E_PROJECTOR: translate('OpenLP.ProjectorConstants', 'Projector/Display Error'),
324 E_INVALID_DATA: translate('OpenLP.ProjectorConstants', 'Invalid packet received'),
325 E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
326 E_ERROR: translate('OpenLP.ProjectorConstants', 'Error condition detected'),
327 E_CLASS: translate('OpenLP.ProjectorConstants', 'PJLink class not supported'),
328 E_PREFIX: translate('OpenLP.ProjectorConstants', 'Invalid prefix character'),
329 E_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',371 E_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
330 'The connection was refused by the peer (or timed out)'),372 'The connection was refused by the peer (or timed out)'),
331 E_REMOTE_HOST_CLOSED_CONNECTION: translate('OpenLP.ProjectorConstants',373 E_COVER: translate('OpenLP.ProjectorConstants', 'Projector cover open detected'),
332 'The remote host closed the connection'),374 E_CLASS: translate('OpenLP.ProjectorConstants', 'PJLink class not supported'),
375 E_DATAGRAM_TOO_LARGE: translate('OpenLP.ProjectorConstants',
376 "The datagram was larger than the operating system's limit"),
377 E_ERROR: translate('OpenLP.ProjectorConstants', 'Error condition detected'),
378 E_FAN: translate('OpenLP.ProjectorConstants', 'Projector fan error'),
379 E_FILTER: translate('OpenLP.ProjectorConstants', 'Projector check filter'),
380 E_GENERAL: translate('OpenLP.ProjectorConstants', 'General projector error'),
333 E_HOST_NOT_FOUND: translate('OpenLP.ProjectorConstants', 'The host address was not found'),381 E_HOST_NOT_FOUND: translate('OpenLP.ProjectorConstants', 'The host address was not found'),
334 E_SOCKET_ACCESS: translate('OpenLP.ProjectorConstants',382 E_INVALID_DATA: translate('OpenLP.ProjectorConstants', 'PJLink invalid packet received'),
335 'The socket operation failed because the application '383 E_LAMP: translate('OpenLP.ProjectorConstants', 'Projector lamp error'),
336 'lacked the required privileges'),
337 E_SOCKET_RESOURCE: translate('OpenLP.ProjectorConstants',
338 'The local system ran out of resources (e.g., too many sockets)'),
339 E_SOCKET_TIMEOUT: translate('OpenLP.ProjectorConstants',
340 'The socket operation timed out'),
341 E_DATAGRAM_TOO_LARGE: translate('OpenLP.ProjectorConstants',
342 'The datagram was larger than the operating system\'s limit'),
343 E_NETWORK: translate('OpenLP.ProjectorConstants',384 E_NETWORK: translate('OpenLP.ProjectorConstants',
344 'An error occurred with the network (Possibly someone pulled the plug?)'),385 'An error occurred with the network (Possibly someone pulled the plug?)'),
345 E_ADDRESS_IN_USE: translate('OpenLP.ProjectorConstants',386 E_NO_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'PJlink authentication Mismatch Error'),
346 'The address specified with socket.bind() '387 E_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Projector not connected error'),
347 'is already in use and was set to be exclusive'),388 E_PARAMETER: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR2: Invalid Parameter"'),
348 E_SOCKET_ADDRESS_NOT_AVAILABLE: translate('OpenLP.ProjectorConstants',389 E_PREFIX: translate('OpenLP.ProjectorConstants', 'PJLink Invalid prefix character'),
349 'The address specified to socket.bind() '390 E_PROJECTOR: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR4: Projector/Display Error"'),
350 'does not belong to the host'),
351 E_UNSUPPORTED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
352 'The requested socket operation is not supported by the local '
353 'operating system (e.g., lack of IPv6 support)'),
354 E_PROXY_AUTHENTICATION_REQUIRED: translate('OpenLP.ProjectorConstants',391 E_PROXY_AUTHENTICATION_REQUIRED: translate('OpenLP.ProjectorConstants',
355 'The socket is using a proxy, '392 'The socket is using a proxy, '
356 'and the proxy requires authentication'),393 'and the proxy requires authentication'),
357 E_SLS_HANDSHAKE_FAILED: translate('OpenLP.ProjectorConstants',394 E_PROXY_CONNECTION_CLOSED: translate('OpenLP.ProjectorConstants',
358 'The SSL/TLS handshake failed'),395 'The connection to the proxy server was closed unexpectedly '
359 E_UNFINISHED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',396 '(before the connection to the final peer was established)'),
360 'The last operation attempted has not finished yet '
361 '(still in progress in the background)'),
362 E_PROXY_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',397 E_PROXY_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
363 'Could not contact the proxy server because the connection '398 'Could not contact the proxy server because the connection '
364 'to that server was denied'),399 'to that server was denied'),
365 E_PROXY_CONNECTION_CLOSED: translate('OpenLP.ProjectorConstants',
366 'The connection to the proxy server was closed unexpectedly '
367 '(before the connection to the final peer was established)'),
368 E_PROXY_CONNECTION_TIMEOUT: translate('OpenLP.ProjectorConstants',400 E_PROXY_CONNECTION_TIMEOUT: translate('OpenLP.ProjectorConstants',
369 'The connection to the proxy server timed out or the proxy '401 'The connection to the proxy server timed out or the proxy '
370 'server stopped responding in the authentication phase.'),402 'server stopped responding in the authentication phase.'),
@@ -373,51 +405,91 @@
373 E_PROXY_PROTOCOL: translate('OpenLP.ProjectorConstants',405 E_PROXY_PROTOCOL: translate('OpenLP.ProjectorConstants',
374 'The connection negotiation with the proxy server failed because the '406 'The connection negotiation with the proxy server failed because the '
375 'response from the proxy server could not be understood'),407 'response from the proxy server could not be understood'),
376 E_UNKNOWN_SOCKET_ERROR: translate('OpenLP.ProjectorConstants', 'An unidentified error occurred'),408 E_REMOTE_HOST_CLOSED_CONNECTION: translate('OpenLP.ProjectorConstants',
377 S_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not connected'),409 'The remote host closed the connection'),
410 E_SLS_HANDSHAKE_FAILED: translate('OpenLP.ProjectorConstants',
411 'The SSL/TLS handshake failed'),
412 E_SOCKET_ADDRESS_NOT_AVAILABLE: translate('OpenLP.ProjectorConstants',
413 'The address specified to socket.bind() '
414 'does not belong to the host'),
415 E_SOCKET_ACCESS: translate('OpenLP.ProjectorConstants',
416 'The socket operation failed because the application '
417 'lacked the required privileges'),
418 E_SOCKET_RESOURCE: translate('OpenLP.ProjectorConstants',
419 'The local system ran out of resources (e.g., too many sockets)'),
420 E_SOCKET_TIMEOUT: translate('OpenLP.ProjectorConstants',
421 'The socket operation timed out'),
422 E_TEMP: translate('OpenLP.ProjectorConstants', 'Projector high temperature detected'),
423 E_UNAVAILABLE: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR3: Busy"'),
424 E_UNDEFINED: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR1: Undefined Command"'),
425 E_UNFINISHED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
426 'The last operation attempted has not finished yet '
427 '(still in progress in the background)'),
428 E_UNKNOWN: translate('OpenLP.ProjectorConstants', 'Unknown condiction detected'),
429 E_UNKNOWN_SOCKET_ERROR: translate('OpenLP.ProjectorConstants', 'An unidentified socket error occurred'),
430 E_UNSUPPORTED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
431 'The requested socket operation is not supported by the local '
432 'operating system (e.g., lack of IPv6 support)'),
433 E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
434 S_BOUND: translate('OpenLP.ProjectorConstants', 'Socket is bount to an address or port'),
435 S_CLOSING: translate('OpenLP.ProjectorConstants', 'Socket is about to close'),
436 S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),
378 S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'),437 S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'),
379 S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),438 S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),
380 S_STATUS: translate('OpenLP.ProjectorConstants', 'Getting status'),439 S_HOST_LOOKUP: translate('OpenLP.ProjectorConstants', 'Performing a host name lookup'),
440 S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),
441 S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),
442 S_LISTENING: translate('OpenLP.ProjectorConstants', 'Socket it listening (internal use only)'),
443 S_NETWORK_IDLE: translate('OpenLP.ProjectorConstants', 'No network activity at this time'),
444 S_NETWORK_RECEIVING: translate('OpenLP.ProjectorConstants', 'Received data'),
445 S_NETWORK_SENDING: translate('OpenLP.ProjectorConstants', 'Sending data'),
446 S_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not Connected'),
381 S_OFF: translate('OpenLP.ProjectorConstants', 'Off'),447 S_OFF: translate('OpenLP.ProjectorConstants', 'Off'),
382 S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),448 S_OK: translate('OpenLP.ProjectorConstants', 'OK'),
449 S_ON: translate('OpenLP.ProjectorConstants', 'Power is on'),
383 S_STANDBY: translate('OpenLP.ProjectorConstants', 'Power in standby'),450 S_STANDBY: translate('OpenLP.ProjectorConstants', 'Power in standby'),
451 S_STATUS: translate('OpenLP.ProjectorConstants', 'Getting status'),
384 S_WARMUP: translate('OpenLP.ProjectorConstants', 'Warmup in progress'),452 S_WARMUP: translate('OpenLP.ProjectorConstants', 'Warmup in progress'),
385 S_ON: translate('OpenLP.ProjectorConstants', 'Power is on'),453}
386 S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),454
387 S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),455# Map ERST reply positions to equipment
388 S_NETWORK_SENDING: translate('OpenLP.ProjectorConstants', 'Sending data'),456PJLINK_ERST_LIST = {
389 S_NETWORK_RECEIVED: translate('OpenLP.ProjectorConstants', 'Received data')457 "FAN": translate('OpenLP.PJLink', 'Fan'),
390}458 "LAMP": translate('OpenLP.PJLink', 'Lamp'),
391459 "TEMP": translate('OpenLP.PJLink', 'Temperature'),
392# Map ERST return code positions to equipment460 "COVER": translate('OpenLP.PJLink', 'Cover'),
461 "FILTER": translate('OpenLP.PJLink', 'Filter'),
462 "OTHER": translate('OpenPL.PJLink', 'Other')
463}
464
465# Map projector item to ERST data position
393PJLINK_ERST_DATA = {466PJLINK_ERST_DATA = {
394 'DATA_LENGTH': 6,467 'DATA_LENGTH': 6, # Zero based so enums are 0-5
468 'FAN': 0,
469 'LAMP': 1,
470 'TEMP': 2,
471 'COVER': 3,
472 'FILTER': 4,
473 'OTHER': 5,
395 0: 'FAN',474 0: 'FAN',
396 1: 'LAMP',475 1: 'LAMP',
397 2: 'TEMP',476 2: 'TEMP',
398 3: 'COVER',477 3: 'COVER',
399 4: 'FILTER',478 4: 'FILTER',
400 5: 'OTHER',479 5: 'OTHER'
401 'FAN': 0,
402 'LAMP': 1,
403 'TEMP': 2,
404 'COVER': 3,
405 'FILTER': 4,
406 'OTHER': 5
407}480}
408481
409# Map for ERST return codes to string482# Map ERST reply codes to string
410PJLINK_ERST_STATUS = {483PJLINK_ERST_STATUS = {
411 '0': 'OK',484 '0': S_OK,
412 '1': ERROR_STRING[E_WARN],485 '1': E_WARN,
413 '2': ERROR_STRING[E_ERROR],486 '2': E_ERROR,
414 'OK': '0',487 S_OK: '0',
415 E_OK: '0',
416 E_WARN: '1',488 E_WARN: '1',
417 E_ERROR: '2'489 E_ERROR: '2'
418}490}
419491
420# Map for POWR return codes to status code492# Map POWR return codes to status code
421PJLINK_POWR_STATUS = {493PJLINK_POWR_STATUS = {
422 '0': S_STANDBY,494 '0': S_STANDBY,
423 '1': S_ON,495 '1': S_ON,
424496
=== modified file 'openlp/core/projectors/manager.py'
--- openlp/core/projectors/manager.py 2017-12-29 09:15:48 +0000
+++ openlp/core/projectors/manager.py 2018-01-03 05:54:24 +0000
@@ -35,9 +35,25 @@
35from openlp.core.common.settings import Settings35from openlp.core.common.settings import Settings
36from openlp.core.lib.ui import create_widget_action36from openlp.core.lib.ui import create_widget_action
37from openlp.core.projectors import DialogSourceStyle37from openlp.core.projectors import DialogSourceStyle
38from openlp.core.projectors.constants import ERROR_MSG, ERROR_STRING, E_AUTHENTICATION, E_ERROR, \38from openlp.core.projectors.constants import \
39 E_NETWORK, E_NOT_CONNECTED, E_UNKNOWN_SOCKET_ERROR, STATUS_STRING, S_CONNECTED, S_CONNECTING, S_COOLDOWN, \39 E_AUTHENTICATION, \
40 S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP40 E_ERROR, \
41 E_NETWORK, \
42 E_NOT_CONNECTED, \
43 E_UNKNOWN_SOCKET_ERROR, \
44 S_CONNECTED, \
45 S_CONNECTING, \
46 S_COOLDOWN, \
47 S_INITIALIZE, \
48 S_NOT_CONNECTED, \
49 S_OFF, \
50 S_ON, \
51 S_STANDBY, \
52 S_WARMUP, \
53 STATUS_CODE, \
54 STATUS_MSG, \
55 QSOCKET_STATE
56
41from openlp.core.projectors.db import ProjectorDB57from openlp.core.projectors.db import ProjectorDB
42from openlp.core.projectors.editform import ProjectorEditForm58from openlp.core.projectors.editform import ProjectorEditForm
43from openlp.core.projectors.pjlink import PJLink, PJLinkUDP59from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
@@ -440,11 +456,12 @@
440 :param opt: Needed by PyQt5456 :param opt: Needed by PyQt5
441 """457 """
442 projector = item.data(QtCore.Qt.UserRole)458 projector = item.data(QtCore.Qt.UserRole)
443 if projector.link.state() != projector.link.ConnectedState:459 if QSOCKET_STATE[projector.link.state()] != S_CONNECTED:
444 try:460 try:
461 log.debug('ProjectorManager: Calling connect_to_host() on "{ip}"'.format(ip=projector.link.ip))
445 projector.link.connect_to_host()462 projector.link.connect_to_host()
446 except:463 except:
447 pass464 log.debug('ProjectorManager: "{ip}" already connected - skipping'.format(ip=projector.link.ip))
448 return465 return
449466
450 def on_connect_projector(self, opt=None):467 def on_connect_projector(self, opt=None):
@@ -647,7 +664,7 @@
647 'Other info'),664 'Other info'),
648 data=projector.link.other_info)665 data=projector.link.other_info)
649 message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Power status'),666 message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Power status'),
650 data=ERROR_MSG[projector.link.power])667 data=STATUS_MSG[projector.link.power])
651 message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Shutter is'),668 message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Shutter is'),
652 data=translate('OpenLP.ProjectorManager', 'Closed')669 data=translate('OpenLP.ProjectorManager', 'Closed')
653 if projector.link.shutter670 if projector.link.shutter
@@ -692,7 +709,7 @@
692 else:709 else:
693 message += '<b>{data}</b>'.format(data=translate('OpenLP.ProjectorManager', 'Current errors/warnings'))710 message += '<b>{data}</b>'.format(data=translate('OpenLP.ProjectorManager', 'Current errors/warnings'))
694 for (key, val) in projector.link.projector_errors.items():711 for (key, val) in projector.link.projector_errors.items():
695 message += '<b>{key}</b>: {data}<br />'.format(key=key, data=ERROR_MSG[val])712 message += '<b>{key}</b>: {data}<br />'.format(key=key, data=STATUS_MSG[val])
696 QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message)713 QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message)
697714
698 def _add_projector(self, projector):715 def _add_projector(self, projector):
@@ -817,31 +834,18 @@
817 if ip == list_item.link.ip:834 if ip == list_item.link.ip:
818 item = list_item835 item = list_item
819 break836 break
820 message = translate('OpenLP.ProjectorManager', 'No message') if msg is None else msg837 if item is None:
821 if status in STATUS_STRING:838 log.error('ProjectorManager: Unknown item "{ip}" - not updating status'.format(ip=ip))
822 status_code = STATUS_STRING[status]839 return
823 message = ERROR_MSG[status] if msg is None else msg840 elif item.status == status:
824 elif status in ERROR_STRING:841 log.debug('ProjectorManager: No status change for "{ip}" - not updating status'.format(ip=ip))
825 status_code = ERROR_STRING[status]842 return
826 message = ERROR_MSG[status] if msg is None else msg843
827 else:844 item.status = status
828 status_code = status845 item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
829 message = ERROR_MSG[status] if msg is None else msg846 log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=STATUS_CODE[status]))
830 log.debug('({name}) updateStatus(status={status}) message: "{message}"'.format(name=item.link.name,847 item.widget.setIcon(item.icon)
831 status=status_code,848 return self.update_icons()
832 message=message))
833 if status in STATUS_ICONS:
834 if item.status == status:
835 return
836 item.status = status
837 item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
838 if status in ERROR_STRING:
839 status_code = ERROR_STRING[status]
840 elif status in STATUS_STRING:
841 status_code = STATUS_STRING[status]
842 log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=status_code))
843 item.widget.setIcon(item.icon)
844 self.update_icons()
845849
846 def get_toolbar_item(self, name, enabled=False, hidden=False):850 def get_toolbar_item(self, name, enabled=False, hidden=False):
847 item = self.one_toolbar.findChild(QtWidgets.QAction, name)851 item = self.one_toolbar.findChild(QtWidgets.QAction, name)
@@ -877,7 +881,7 @@
877 self.get_toolbar_item('show_projector_multiple', hidden=True)881 self.get_toolbar_item('show_projector_multiple', hidden=True)
878 elif count == 1:882 elif count == 1:
879 projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)883 projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)
880 connected = projector.link.state() == projector.link.ConnectedState884 connected = QSOCKET_STATE[projector.link.state()] == S_CONNECTED
881 power = projector.link.power == S_ON885 power = projector.link.power == S_ON
882 self.get_toolbar_item('connect_projector_multiple', hidden=True)886 self.get_toolbar_item('connect_projector_multiple', hidden=True)
883 self.get_toolbar_item('disconnect_projector_multiple', hidden=True)887 self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
884888
=== modified file 'openlp/core/projectors/pjlink.py'
--- openlp/core/projectors/pjlink.py 2017-12-29 09:15:48 +0000
+++ openlp/core/projectors/pjlink.py 2018-01-03 05:54:24 +0000
@@ -54,11 +54,12 @@
5454
55from openlp.core.common import qmd5_hash55from openlp.core.common import qmd5_hash
56from openlp.core.common.i18n import translate56from openlp.core.common.i18n import translate
57from openlp.core.projectors.constants import CONNECTION_ERRORS, CR, ERROR_MSG, ERROR_STRING, \57from openlp.core.projectors.constants import CONNECTION_ERRORS, PJLINK_CLASS, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \
58 E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, E_OK, \58 PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PREFIX, PJLINK_PORT, PJLINK_POWR_STATUS, \
59 E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, PJLINK_ERST_DATA, \59 PJLINK_SUFFIX, PJLINK_VALID_CMD, PROJECTOR_STATE, STATUS_CODE, STATUS_MSG, QSOCKET_STATE, \
60 PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_POWR_STATUS, PJLINK_VALID_CMD, \60 E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, \
61 STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_QSOCKET_STATE, S_STATUS61 E_OK, E_SOCKET_TIMEOUT, \
62 S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS
6263
63log = logging.getLogger(__name__)64log = logging.getLogger(__name__)
64log.debug('pjlink loaded')65log.debug('pjlink loaded')
@@ -69,12 +70,9 @@
69SocketError = QtNetwork.QAbstractSocket.SocketError70SocketError = QtNetwork.QAbstractSocket.SocketError
70SocketSTate = QtNetwork.QAbstractSocket.SocketState71SocketSTate = QtNetwork.QAbstractSocket.SocketState
7172
72PJLINK_PREFIX = '%'
73PJLINK_CLASS = '1' # Default to class 1 until we query the projector
74# Add prefix here, but defer linkclass expansion until later when we have the actual73# Add prefix here, but defer linkclass expansion until later when we have the actual
75# PJLink class for the command74# PJLink class for the command
76PJLINK_HEADER = '{prefix}{{linkclass}}'.format(prefix=PJLINK_PREFIX)75PJLINK_HEADER = '{prefix}{{linkclass}}'.format(prefix=PJLINK_PREFIX)
77PJLINK_SUFFIX = CR
7876
7977
80class PJLinkUDP(QtNetwork.QUdpSocket):78class PJLinkUDP(QtNetwork.QUdpSocket):
@@ -136,8 +134,9 @@
136 """134 """
137 Initialize instance variables. Also used to reset projector-specific information to default.135 Initialize instance variables. Also used to reset projector-specific information to default.
138 """136 """
137 conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
139 log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip,138 log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip,
140 state=S_QSOCKET_STATE[self.state()]))139 state=conn_state))
141 self.fan = None # ERST140 self.fan = None # ERST
142 self.filter_time = None # FILT141 self.filter_time = None # FILT
143 self.lamp = None # LAMP142 self.lamp = None # LAMP
@@ -183,42 +182,25 @@
183 # Due to some replies should stay as mixed-case, validate using separate uppercase check182 # Due to some replies should stay as mixed-case, validate using separate uppercase check
184 _data = data.upper()183 _data = data.upper()
185 # Check if we have a future command not available yet184 # Check if we have a future command not available yet
186 if cmd not in PJLINK_VALID_CMD:185 if cmd not in self.pjlink_functions:
187 log.error('({ip}) Ignoring command="{cmd}" (Invalid/Unknown)'.format(ip=self.ip, cmd=cmd))186 log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd))
188 return187 return
189 elif _data == 'OK':188 elif _data == 'OK':
190 log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=self.ip, cmd=cmd))189 log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=self.ip, cmd=cmd))
191 # A command returned successfully, so do a query on command to verify status190 # A command returned successfully, so do a query on command to verify status
192 return self.send_command(cmd=cmd)191 return self.send_command(cmd=cmd)
193 elif cmd not in self.pjlink_functions:
194 log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd))
195 return
196 elif _data in PJLINK_ERRORS:192 elif _data in PJLINK_ERRORS:
197 # Oops - projector error193 # Oops - projector error
198 log.error('({ip}) Projector returned error "{data}"'.format(ip=self.ip, data=data))194 log.error('({ip}) {cmd}: {err}'.format(ip=self.ip,
199 if _data == PJLINK_ERRORS[E_AUTHENTICATION]:195 cmd=cmd,
200 # Authentication error196 err=STATUS_MSG[PJLINK_ERRORS[_data]]))
197 if PJLINK_ERRORS[_data] == E_AUTHENTICATION:
201 self.disconnect_from_host()198 self.disconnect_from_host()
202 self.change_status(E_AUTHENTICATION)
203 log.debug('({ip}) emitting projectorAuthentication() signal'.format(ip=self.ip))
204 self.projectorAuthentication.emit(self.name)199 self.projectorAuthentication.emit(self.name)
205 elif _data == PJLINK_ERRORS[E_UNDEFINED]:200 return self.change_status(status=E_AUTHENTICATION)
206 # Projector does not recognize command
207 self.change_status(E_UNDEFINED, '{error}: "{data}"'.format(error=ERROR_MSG[E_UNDEFINED],
208 data=cmd))
209 elif _data == PJLINK_ERRORS[E_PARAMETER]:
210 # Invalid parameter
211 self.change_status(E_PARAMETER)
212 elif _data == PJLINK_ERRORS[E_UNAVAILABLE]:
213 # Projector busy
214 self.change_status(E_UNAVAILABLE)
215 elif _data == PJLINK_ERRORS[E_PROJECTOR]:
216 # Projector/display error
217 self.change_status(E_PROJECTOR)
218 return
219 # Command checks already passed201 # Command checks already passed
220 log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd))202 log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd))
221 self.pjlink_functions[cmd](data)203 self.pjlink_functions[cmd](data=data)
222204
223 def process_avmt(self, data):205 def process_avmt(self, data):
224 """206 """
@@ -313,22 +295,22 @@
313 data[PJLINK_ERST_DATA['COVER']],295 data[PJLINK_ERST_DATA['COVER']],
314 data[PJLINK_ERST_DATA['FILTER']],296 data[PJLINK_ERST_DATA['FILTER']],
315 data[PJLINK_ERST_DATA['OTHER']])297 data[PJLINK_ERST_DATA['OTHER']])
316 if fan != PJLINK_ERST_STATUS[E_OK]:298 if fan != PJLINK_ERST_STATUS[S_OK]:
317 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Fan')] = \299 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Fan')] = \
318 PJLINK_ERST_STATUS[fan]300 PJLINK_ERST_STATUS[fan]
319 if lamp != PJLINK_ERST_STATUS[E_OK]:301 if lamp != PJLINK_ERST_STATUS[S_OK]:
320 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Lamp')] = \302 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Lamp')] = \
321 PJLINK_ERST_STATUS[lamp]303 PJLINK_ERST_STATUS[lamp]
322 if temp != PJLINK_ERST_STATUS[E_OK]:304 if temp != PJLINK_ERST_STATUS[S_OK]:
323 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Temperature')] = \305 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Temperature')] = \
324 PJLINK_ERST_STATUS[temp]306 PJLINK_ERST_STATUS[temp]
325 if cover != PJLINK_ERST_STATUS[E_OK]:307 if cover != PJLINK_ERST_STATUS[S_OK]:
326 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Cover')] = \308 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Cover')] = \
327 PJLINK_ERST_STATUS[cover]309 PJLINK_ERST_STATUS[cover]
328 if filt != PJLINK_ERST_STATUS[E_OK]:310 if filt != PJLINK_ERST_STATUS[S_OK]:
329 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Filter')] = \311 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Filter')] = \
330 PJLINK_ERST_STATUS[filt]312 PJLINK_ERST_STATUS[filt]
331 if other != PJLINK_ERST_STATUS[E_OK]:313 if other != PJLINK_ERST_STATUS[S_OK]:
332 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Other')] = \314 self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Other')] = \
333 PJLINK_ERST_STATUS[other]315 PJLINK_ERST_STATUS[other]
334 return316 return
@@ -373,8 +355,18 @@
373355
374 :param data: Currently selected source356 :param data: Currently selected source
375 """357 """
358 # First, see if we have a valid input based on what is installed (if available)
359 if self.source_available is not None:
360 # We have available inputs, so verify it's in the list
361 if data not in self.source_available:
362 log.warn('({ip}) Input source not listed in available sources - ignoring'.format(ip=self.ip))
363 return
364 elif data not in PJLINK_DEFAULT_CODES:
365 # Hmm - no sources available yet, so check with PJLink defaults
366 log.warn('({ip}) Input source not listed as a PJLink available source - ignoring'.format(ip=self.ip))
367 return
376 self.source = data368 self.source = data
377 log.info('({ip}) Setting data source to "{data}"'.format(ip=self.ip, data=self.source))369 log.debug('({ip}) Setting data source to "{data}"'.format(ip=self.ip, data=self.source))
378 return370 return
379371
380 def process_inst(self, data):372 def process_inst(self, data):
@@ -390,7 +382,6 @@
390 sources.append(source)382 sources.append(source)
391 sources.sort()383 sources.sort()
392 self.source_available = sources384 self.source_available = sources
393 self.projectorUpdateIcons.emit()
394 log.debug('({ip}) Setting projector sources_available to "{data}"'.format(ip=self.ip,385 log.debug('({ip}) Setting projector sources_available to "{data}"'.format(ip=self.ip,
395 data=self.source_available))386 data=self.source_available))
396 return387 return
@@ -551,17 +542,15 @@
551 return542 return
552 elif self.sw_version is None:543 elif self.sw_version is None:
553 log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=self.ip, data=data))544 log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=self.ip, data=data))
554 self.sw_version = data
555 self.db_update = True
556 else:545 else:
557 # Compare software version and see if we got the same projector546 if self.sw_version != data:
558 if self.serial_no != data:
559 log.warning('({ip}) Projector software version does not match saved '547 log.warning('({ip}) Projector software version does not match saved '
560 'software version'.format(ip=self.ip))548 'software version'.format(ip=self.ip))
561 log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.sw_version))549 log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.sw_version))
562 log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data))550 log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data))
563 log.warning('({ip}) Saving new serial number as sw_version_received'.format(ip=self.ip))551 log.warning('({ip}) Updating software version'.format(ip=self.ip))
564 self.sw_version_received = data552 self.sw_version = data
553 self.db_update = True
565554
566555
567class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):556class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
@@ -678,7 +667,7 @@
678 Retrieve information from projector that changes.667 Retrieve information from projector that changes.
679 Normally called by timer().668 Normally called by timer().
680 """669 """
681 if self.state() != S_QSOCKET_STATE['ConnectedState']:670 if QSOCKET_STATE[self.state()] != S_CONNECTED:
682 log.warning('({ip}) poll_loop(): Not connected - returning'.format(ip=self.ip))671 log.warning('({ip}) poll_loop(): Not connected - returning'.format(ip=self.ip))
683 return672 return
684 log.debug('({ip}) poll_loop(): Updating projector status'.format(ip=self.ip))673 log.debug('({ip}) poll_loop(): Updating projector status'.format(ip=self.ip))
@@ -688,13 +677,8 @@
688 self.timer.setInterval(self.poll_time)677 self.timer.setInterval(self.poll_time)
689 # Restart timer678 # Restart timer
690 self.timer.start()679 self.timer.start()
691 # These commands may change during connection
692 check_list = ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']
693 if self.pjlink_class == '2':
694 check_list.extend(['FILT', 'FREZ'])
695 for command in check_list:
696 self.send_command(command)
697 # The following commands do not change, so only check them once680 # The following commands do not change, so only check them once
681 # Call them first in case other functions rely on something here
698 if self.power == S_ON and self.source_available is None:682 if self.power == S_ON and self.source_available is None:
699 self.send_command('INST')683 self.send_command('INST')
700 if self.other_info is None:684 if self.other_info is None:
@@ -715,22 +699,28 @@
715 self.send_command('RFIL')699 self.send_command('RFIL')
716 if self.model_lamp is None:700 if self.model_lamp is None:
717 self.send_command('RLMP')701 self.send_command('RLMP')
702 # These commands may change during connection
703 check_list = ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']
704 if self.pjlink_class == '2':
705 check_list.extend(['FILT', 'FREZ'])
706 for command in check_list:
707 self.send_command(command)
718708
719 def _get_status(self, status):709 def _get_status(self, status):
720 """710 """
721 Helper to retrieve status/error codes and convert to strings.711 Helper to retrieve status/error codes and convert to strings.
722712
723 :param status: Status/Error code713 :param status: Status/Error code
724 :returns: (Status/Error code, String)714 :returns: tuple (-1 if code not INT, None)
715 :returns: tuple (string: code as string, None if no description)
716 :returns: tuple (string: code as string, string: Status/Error description)
725 """717 """
726 if not isinstance(status, int):718 if not isinstance(status, int):
727 return -1, 'Invalid status code'719 return -1, None
728 elif status in ERROR_STRING:720 elif status not in STATUS_MSG:
729 return ERROR_STRING[status], ERROR_MSG[status]721 return None, None
730 elif status in STATUS_STRING:
731 return STATUS_STRING[status], ERROR_MSG[status]
732 else:722 else:
733 return status, translate('OpenLP.PJLink', 'Unknown status')723 return STATUS_CODE[status], STATUS_MSG[status]
734724
735 def change_status(self, status, msg=None):725 def change_status(self, status, msg=None):
736 """726 """
@@ -740,19 +730,27 @@
740 :param status: Status code730 :param status: Status code
741 :param msg: Optional message731 :param msg: Optional message
742 """732 """
743 message = translate('OpenLP.PJLink', 'No message') if msg is None else msg733 if status in STATUS_CODE:
744 (code, message) = self._get_status(status)734 log.debug('({ip}) Changing status to {status} '
745 if msg is not None:735 '"{msg}"'.format(ip=self.ip,
746 message = msg736 status=STATUS_CODE[status],
737 msg=msg if msg is not None else STATUS_MSG[status]))
738 else:
739 log.warning('({ip}) Unknown status change code: {code}'.format(ip=self.ip,
740 code=status))
741 return
747 if status in CONNECTION_ERRORS:742 if status in CONNECTION_ERRORS:
748 # Projector, connection state743 # Connection state error affects both socket and projector
749 self.projector_status = self.error_status = self.status_connect = E_NOT_CONNECTED744 self.error_status = status
750 elif status >= S_NOT_CONNECTED and status < S_STATUS:745 self.status_connect = E_NOT_CONNECTED
746 elif status >= S_NOT_CONNECTED and status in QSOCKET_STATE:
747 # Socket connection status update
751 self.status_connect = status748 self.status_connect = status
752 self.projector_status = S_NOT_CONNECTED749 elif status >= S_NOT_CONNECTED and status in PROJECTOR_STATE:
753 elif status <= S_INFO:750 # Only affects the projector status
754 self.status_connect = S_CONNECTED
755 self.projector_status = status751 self.projector_status = status
752
753 # These log entries are for troubleshooting only
756 (status_code, status_message) = self._get_status(self.status_connect)754 (status_code, status_message) = self._get_status(self.status_connect)
757 log.debug('({ip}) status_connect: {code}: "{message}"'.format(ip=self.ip,755 log.debug('({ip}) status_connect: {code}: "{message}"'.format(ip=self.ip,
758 code=status_code,756 code=status_code,
@@ -765,6 +763,15 @@
765 log.debug('({ip}) error_status: {code}: "{message}"'.format(ip=self.ip,763 log.debug('({ip}) error_status: {code}: "{message}"'.format(ip=self.ip,
766 code=status_code,764 code=status_code,
767 message=status_message if msg is None else msg))765 message=status_message if msg is None else msg))
766
767 # Now that we logged extra information for debugging, broadcast the original change/message
768 (code, message) = self._get_status(status)
769 if msg is not None:
770 message = msg
771 elif message is None:
772 # No message for status code
773 message = translate('OpenLP.PJLink', 'No message') if msg is None else msg
774
768 self.changeStatus.emit(self.ip, status, message)775 self.changeStatus.emit(self.ip, status, message)
769 self.projectorUpdateIcons.emit()776 self.projectorUpdateIcons.emit()
770777
@@ -794,7 +801,7 @@
794 data = decode(read, 'utf-8')801 data = decode(read, 'utf-8')
795 # Possibility of extraneous data on input when reading.802 # Possibility of extraneous data on input when reading.
796 # Clean out extraneous characters in buffer.803 # Clean out extraneous characters in buffer.
797 self.readLine(self.max_size)804 self.read(1024)
798 log.debug('({ip}) check_login() read "{data}"'.format(ip=self.ip, data=data.strip()))805 log.debug('({ip}) check_login() read "{data}"'.format(ip=self.ip, data=data.strip()))
799 # At this point, we should only have the initial login prompt with806 # At this point, we should only have the initial login prompt with
800 # possible authentication807 # possible authentication
@@ -805,6 +812,7 @@
805 # Invalid initial packet - close socket812 # Invalid initial packet - close socket
806 log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.ip))813 log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.ip))
807 return self.disconnect_from_host()814 return self.disconnect_from_host()
815 # Convert the initial login prompt with the expected PJLink normal command format for processing
808 log.debug('({ip}) check_login(): Formatting initial connection prompt to PJLink packet'.format(ip=self.ip))816 log.debug('({ip}) check_login(): Formatting initial connection prompt to PJLink packet'.format(ip=self.ip))
809 return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX,817 return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX,
810 clss='1',818 clss='1',
@@ -895,7 +903,7 @@
895 Get data from TCP socket.903 Get data from TCP socket.
896 """904 """
897 log.debug('({ip}) get_socket(): Reading data'.format(ip=self.ip))905 log.debug('({ip}) get_socket(): Reading data'.format(ip=self.ip))
898 if self.state() != self.ConnectedState:906 if QSOCKET_STATE[self.state()] != S_CONNECTED:
899 log.debug('({ip}) get_socket(): Not connected - returning'.format(ip=self.ip))907 log.debug('({ip}) get_socket(): Not connected - returning'.format(ip=self.ip))
900 self.send_busy = False908 self.send_busy = False
901 return909 return
@@ -907,8 +915,7 @@
907 log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.ip))915 log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.ip))
908 return self.receive_data_signal()916 return self.receive_data_signal()
909 self.socket_timer.stop()917 self.socket_timer.stop()
910 self.get_data(buff=read, ip=self.ip)918 return self.get_data(buff=read, ip=self.ip)
911 return self.receive_data_signal()
912919
913 def get_data(self, buff, ip=None):920 def get_data(self, buff, ip=None):
914 """921 """
@@ -927,13 +934,17 @@
927 data = data_in.strip()934 data = data_in.strip()
928 # Initial packet checks935 # Initial packet checks
929 if (len(data) < 7):936 if (len(data) < 7):
930 return self._trash_buffer(msg='get_data(): Invalid packet - length')937 self._trash_buffer(msg='get_data(): Invalid packet - length')
938 return self.receive_data_signal()
931 elif len(data) > self.max_size:939 elif len(data) > self.max_size:
932 return self._trash_buffer(msg='get_data(): Invalid packet - too long')940 self._trash_buffer(msg='get_data(): Invalid packet - too long')
941 return self.receive_data_signal()
933 elif not data.startswith(PJLINK_PREFIX):942 elif not data.startswith(PJLINK_PREFIX):
934 return self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')943 self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')
944 return self.receive_data_signal()
935 elif '=' not in data:945 elif '=' not in data:
936 return self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')946 self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')
947 return self.receive_data_signal()
937 log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))948 log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))
938 header, data = data.split('=')949 header, data = data.split('=')
939 # At this point, the header should contain:950 # At this point, the header should contain:
@@ -947,15 +958,17 @@
947 except ValueError as e:958 except ValueError as e:
948 self.change_status(E_INVALID_DATA)959 self.change_status(E_INVALID_DATA)
949 log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in))960 log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in))
950 return self._trash_buffer('get_data(): Expected header + command + data')961 self._trash_buffer('get_data(): Expected header + command + data')
962 return self.receive_data_signal()
951 if cmd not in PJLINK_VALID_CMD:963 if cmd not in PJLINK_VALID_CMD:
952 log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))964 log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
953 return self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))965 self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
966 return self.receive_data_signal()
954 if int(self.pjlink_class) < int(version):967 if int(self.pjlink_class) < int(version):
955 log.warning('({ip}) get_data(): Projector returned class reply higher '968 log.warning('({ip}) get_data(): Projector returned class reply higher '
956 'than projector stated class'.format(ip=self.ip))969 'than projector stated class'.format(ip=self.ip))
957 self.send_busy = False970 self.process_command(cmd, data)
958 return self.process_command(cmd, data)971 return self.receive_data_signal()
959972
960 @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)973 @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
961 def get_error(self, err):974 def get_error(self, err):
@@ -993,7 +1006,7 @@
993 :param salt: Optional salt for md5 hash initial authentication1006 :param salt: Optional salt for md5 hash initial authentication
994 :param priority: Option to send packet now rather than queue it up1007 :param priority: Option to send packet now rather than queue it up
995 """1008 """
996 if self.state() != self.ConnectedState:1009 if QSOCKET_STATE[self.state()] != S_CONNECTED:
997 log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))1010 log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
998 return self.reset_information()1011 return self.reset_information()
999 if cmd not in PJLINK_VALID_CMD:1012 if cmd not in PJLINK_VALID_CMD:
@@ -1018,7 +1031,7 @@
1018 header=header,1031 header=header,
1019 command=cmd,1032 command=cmd,
1020 options=opts,1033 options=opts,
1021 suffix=CR)1034 suffix=PJLINK_SUFFIX)
1022 if out in self.priority_queue:1035 if out in self.priority_queue:
1023 log.debug('({ip}) send_command(): Already in priority queue - skipping'.format(ip=self.ip))1036 log.debug('({ip}) send_command(): Already in priority queue - skipping'.format(ip=self.ip))
1024 elif out in self.send_queue:1037 elif out in self.send_queue:
@@ -1044,9 +1057,10 @@
1044 """1057 """
1045 # Funny looking data check, but it's a quick check for data=None1058 # Funny looking data check, but it's a quick check for data=None
1046 log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.ip, data=data.strip() if data else data))1059 log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.ip, data=data.strip() if data else data))
1060 conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
1047 log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.ip,1061 log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.ip,
1048 data=S_QSOCKET_STATE[self.state()]))1062 data=conn_state))
1049 if self.state() != self.ConnectedState:1063 if QSOCKET_STATE[self.state()] != S_CONNECTED:
1050 log.debug('({ip}) _send_command() Not connected - abort'.format(ip=self.ip))1064 log.debug('({ip}) _send_command() Not connected - abort'.format(ip=self.ip))
1051 self.send_busy = False1065 self.send_busy = False
1052 return self.disconnect_from_host()1066 return self.disconnect_from_host()
@@ -1088,10 +1102,11 @@
1088 """1102 """
1089 Initiate connection to projector.1103 Initiate connection to projector.
1090 """1104 """
1091 log.debug('{ip}) connect_to_host(): Starting connection'.format(ip=self.ip))1105 log.debug('({ip}) connect_to_host(): Starting connection'.format(ip=self.ip))
1092 if self.state() == self.ConnectedState:1106 if QSOCKET_STATE[self.state()] == S_CONNECTED:
1093 log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))1107 log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
1094 return1108 return
1109 self.error_status = S_OK
1095 self.change_status(S_CONNECTING)1110 self.change_status(S_CONNECTING)
1096 self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port))1111 self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port))
10971112
@@ -1100,12 +1115,13 @@
1100 """1115 """
1101 Close socket and cleanup.1116 Close socket and cleanup.
1102 """1117 """
1103 if abort or self.state() != self.ConnectedState:1118 if abort or QSOCKET_STATE[self.state()] != S_NOT_CONNECTED:
1104 if abort:1119 if abort:
1105 log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))1120 log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
1121 self.abort()
1106 else:1122 else:
1107 log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.ip))1123 log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.ip))
1108 self.disconnectFromHost()1124 self.disconnectFromHost()
1109 try:1125 try:
1110 self.readyRead.disconnect(self.get_socket)1126 self.readyRead.disconnect(self.get_socket)
1111 except TypeError:1127 except TypeError:
@@ -1201,7 +1217,7 @@
1201 elif src not in self.source_available:1217 elif src not in self.source_available:
1202 return1218 return
1203 log.debug('({ip}) Setting input source to "{data}"'.format(ip=self.ip, data=src))1219 log.debug('({ip}) Setting input source to "{data}"'.format(ip=self.ip, data=src))
1204 self.send_command(cmd='INPT', opts=src)1220 self.send_command(cmd='INPT', opts=src, priority=True)
1205 self.poll_loop()1221 self.poll_loop()
12061222
1207 def set_power_on(self):1223 def set_power_on(self):
@@ -1209,7 +1225,7 @@
1209 Send command to turn power to on.1225 Send command to turn power to on.
1210 """1226 """
1211 log.debug('({ip}) Setting POWR to 1 (on)'.format(ip=self.ip))1227 log.debug('({ip}) Setting POWR to 1 (on)'.format(ip=self.ip))
1212 self.send_command(cmd='POWR', opts='1')1228 self.send_command(cmd='POWR', opts='1', priority=True)
1213 self.poll_loop()1229 self.poll_loop()
12141230
1215 def set_power_off(self):1231 def set_power_off(self):
@@ -1217,7 +1233,7 @@
1217 Send command to turn power to standby.1233 Send command to turn power to standby.
1218 """1234 """
1219 log.debug('({ip}) Setting POWR to 0 (standby)'.format(ip=self.ip))1235 log.debug('({ip}) Setting POWR to 0 (standby)'.format(ip=self.ip))
1220 self.send_command(cmd='POWR', opts='0')1236 self.send_command(cmd='POWR', opts='0', priority=True)
1221 self.poll_loop()1237 self.poll_loop()
12221238
1223 def set_shutter_closed(self):1239 def set_shutter_closed(self):
@@ -1225,7 +1241,7 @@
1225 Send command to set shutter to closed position.1241 Send command to set shutter to closed position.
1226 """1242 """
1227 log.debug('({ip}) Setting AVMT to 11 (shutter closed)'.format(ip=self.ip))1243 log.debug('({ip}) Setting AVMT to 11 (shutter closed)'.format(ip=self.ip))
1228 self.send_command(cmd='AVMT', opts='11')1244 self.send_command(cmd='AVMT', opts='11', priority=True)
1229 self.poll_loop()1245 self.poll_loop()
12301246
1231 def set_shutter_open(self):1247 def set_shutter_open(self):
@@ -1233,8 +1249,9 @@
1233 Send command to set shutter to open position.1249 Send command to set shutter to open position.
1234 """1250 """
1235 log.debug('({ip}) Setting AVMT to "10" (shutter open)'.format(ip=self.ip))1251 log.debug('({ip}) Setting AVMT to "10" (shutter open)'.format(ip=self.ip))
1236 self.send_command(cmd='AVMT', opts='10')1252 self.send_command(cmd='AVMT', opts='10', priority=True)
1237 self.poll_loop()1253 self.poll_loop()
1254 self.projectorUpdateIcons.emit()
12381255
1239 def receive_data_signal(self):1256 def receive_data_signal(self):
1240 """1257 """
12411258
=== modified file 'tests/functional/openlp_core/projectors/test_projector_constants.py'
--- tests/functional/openlp_core/projectors/test_projector_constants.py 2017-11-10 11:59:38 +0000
+++ tests/functional/openlp_core/projectors/test_projector_constants.py 2018-01-03 05:54:24 +0000
@@ -23,12 +23,51 @@
23Package to test the openlp.core.projectors.constants module.23Package to test the openlp.core.projectors.constants module.
24"""24"""
25from unittest import TestCase25from unittest import TestCase
26from openlp.core.projectors import constants
27from openlp.core.projectors.constants import STATUS_CODE, STATUS_MSG
2628
2729
28class TestProjectorConstants(TestCase):30class TestProjectorConstants(TestCase):
29 """31 """
30 Test specific functions in the projector constants module.32 Test specific functions in the projector constants module.
31 """33 """
34 def test_defined_codes_in_status_code(self):
35 """
36 Test defined status/error codes have equivalent strings
37 """
38 check = []
39 missing_str = []
40
41 # GIVEN: List of defined E_* and S_* items defined in constants
42 for item in constants.__dict__:
43 if item.startswith('E_') or item.startswith('S_'):
44 check.append(item)
45
46 # WHEN: Verify defined list against STATUS_STR
47 for item in check:
48 if constants.__dict__[item] not in STATUS_CODE:
49 missing_str.append(item)
50
51 # THEN: There should be no missing items
52 assert 0 == len(missing_str), 'Status string missing: {msg}'.format(msg=missing_str)
53
54 def test_status_code_in_status_message(self):
55 """
56 Test if entries in STATUS_CODE have equivalent descriptions in STATUS_MSG
57 """
58 missing_msg = []
59
60 # GIVEN: Test items
61 check = STATUS_CODE
62
63 # WHEN: Verify each entry in STATUS_MSG against STATUS_CODE
64 for item in check:
65 if item not in STATUS_MSG:
66 missing_msg.append(item)
67
68 # THEN: There should be no missing items
69 assert 0 == len(missing_msg), 'Status message missing: {msg}'.format(msg=missing_msg)
70
32 def test_build_pjlink_video_label(self):71 def test_build_pjlink_video_label(self):
33 """72 """
34 Test building PJLINK_DEFAULT_CODES dictionary73 Test building PJLINK_DEFAULT_CODES dictionary
3574
=== modified file 'tests/functional/openlp_core/projectors/test_projector_pjlink_base.py'
--- tests/functional/openlp_core/projectors/test_projector_pjlink_base.py 2017-12-28 08:22:55 +0000
+++ tests/functional/openlp_core/projectors/test_projector_pjlink_base.py 2018-01-03 05:54:24 +0000
@@ -25,7 +25,7 @@
25from unittest import TestCase25from unittest import TestCase
26from unittest.mock import call, patch, MagicMock26from unittest.mock import call, patch, MagicMock
2727
28from openlp.core.projectors.constants import E_PARAMETER, ERROR_STRING, S_ON, S_CONNECTED, S_QSOCKET_STATE28from openlp.core.projectors.constants import E_PARAMETER, STATUS_CODE, S_ON, S_CONNECTED, QSOCKET_STATE
29from openlp.core.projectors.db import Projector29from openlp.core.projectors.db import Projector
30from openlp.core.projectors.pjlink import PJLink30from openlp.core.projectors.pjlink import PJLink
31from tests.resources.projector.data import TEST1_DATA31from tests.resources.projector.data import TEST1_DATA
@@ -64,7 +64,7 @@
64 # as first parameter64 # as first parameter
65 mock_change_status.called_with(E_PARAMETER,65 mock_change_status.called_with(E_PARAMETER,
66 'change_status should have been called with "{}"'.format(66 'change_status should have been called with "{}"'.format(
67 ERROR_STRING[E_PARAMETER]))67 STATUS_CODE[E_PARAMETER]))
6868
69 @patch.object(pjlink_test, 'disconnect_from_host')69 @patch.object(pjlink_test, 'disconnect_from_host')
70 def test_socket_abort(self, mock_disconnect):70 def test_socket_abort(self, mock_disconnect):
@@ -103,7 +103,7 @@
103 """103 """
104 # GIVEN: Mocks and test data104 # GIVEN: Mocks and test data
105 mock_state = patch.object(self.pjlink_test, 'state').start()105 mock_state = patch.object(self.pjlink_test, 'state').start()
106 mock_state.return_value = S_QSOCKET_STATE['ConnectedState']106 mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
107 mock_timer = patch.object(self.pjlink_test, 'timer').start()107 mock_timer = patch.object(self.pjlink_test, 'timer').start()
108 mock_timer.interval.return_value = 10108 mock_timer.interval.return_value = 10
109 mock_send_command = patch.object(self.pjlink_test, 'send_command').start()109 mock_send_command = patch.object(self.pjlink_test, 'send_command').start()
@@ -116,7 +116,6 @@
116 pjlink.manufacturer = None116 pjlink.manufacturer = None
117 pjlink.model = None117 pjlink.model = None
118 pjlink.pjlink_name = None118 pjlink.pjlink_name = None
119 pjlink.ConnectedState = S_CONNECTED
120 call_list = [119 call_list = [
121 call('POWR'),120 call('POWR'),
122 call('ERST'),121 call('ERST'),
123122
=== modified file 'tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py'
--- tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2017-12-09 11:17:05 +0000
+++ tests/functional/openlp_core/projectors/test_projector_pjlink_cmd_routing.py 2018-01-03 05:54:24 +0000
@@ -24,209 +24,222 @@
24"""24"""
2525
26from unittest import TestCase26from unittest import TestCase
27from unittest.mock import patch, MagicMock27from unittest.mock import MagicMock, call, patch
2828
29import openlp.core.projectors.pjlink29import openlp.core.projectors.pjlink
30from openlp.core.projectors.constants import PJLINK_ERRORS, \30from openlp.core.projectors.constants import PJLINK_ERRORS, PJLINK_PREFIX, STATUS_MSG, \
31 E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED31 E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED
32from openlp.core.projectors.db import Projector32from openlp.core.projectors.db import Projector
33from openlp.core.projectors.pjlink import PJLink33from openlp.core.projectors.pjlink import PJLink
3434
35'''35from tests.resources.projector.data import TEST1_DATA
36from openlp.core.projectors.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \
37 PJLINK_POWR_STATUS, PJLINK_VALID_CMD, E_WARN, E_ERROR, S_OFF, S_STANDBY, S_ON
38'''
39from tests.resources.projector.data import TEST_PIN, TEST1_DATA
40
41pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
42pjlink_test.ip = '127.0.0.1'
4336
4437
45class TestPJLinkRouting(TestCase):38class TestPJLinkRouting(TestCase):
46 """39 """
47 Tests for the PJLink module command routing40 Tests for the PJLink module command routing
48 """41 """
49 def setUp(self):42 def test_get_data_unknown_command(self):
50 '''43 """
51 TestPJLinkCommands part 2 initialization44 Test not a valid command
52 '''45 """
53 self.pjlink_test = PJLink(Projector(**TEST1_DATA), no_poll=True)46 # GIVEN: Test object
5447 log_warning_text = [call('(111.111.111.111) get_data(): Invalid packet - unknown command "UNK"')]
55 def tearDown(self):48 log_debug_text = [call('(111.111.111.111) get_data(ip="111.111.111.111" buffer="b\'%1UNK=Huh?\'"'),
56 '''49 call('(111.111.111.111) get_data(): Checking new data "%1UNK=Huh?"')]
57 TestPJLinkCommands part 2 cleanups50
58 '''51 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
59 self.pjlink_test = None52 patch.object(openlp.core.projectors.pjlink.PJLink, '_trash_buffer') as mock_buffer:
6053
61 @patch.object(openlp.core.projectors.pjlink, 'log')54 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
62 def test_process_command_call_clss(self, mock_log):55 pjlink.pjlink_functions = MagicMock()
56
57 # WHEN: get_data called with an unknown command
58 pjlink.get_data(buff='{prefix}1UNK=Huh?'.format(prefix=PJLINK_PREFIX).encode('utf-8'))
59
60 # THEN: Appropriate log entries should have been made and methods called/not called
61 mock_log.debug.assert_has_calls(log_debug_text)
62 mock_log.warning.assert_has_calls(log_warning_text)
63 assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions'
64 assert mock_buffer.called is True, 'Should have called _trash_buffer'
65
66 def test_process_command_call_clss(self):
63 """67 """
64 Test process_command calls proper function68 Test process_command calls proper function
65 """69 """
70 # GIVEN: Test object and mocks
71 log_debug_calls = [call('(111.111.111.111) Processing command "CLSS" with data "1"'),
72 call('(111.111.111.111) Calling function for CLSS')]
73
74 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
75 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
76
77 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
78
79 # WHEN: process_command is called with valid function and data
80 pjlink.process_command(cmd='CLSS', data='1')
81
82 # THEN: Appropriate log entries should have been made and methods called
83 mock_log.debug.assert_has_calls(log_debug_calls)
84 mock_process_clss.assert_called_once_with(data='1')
85
86 def test_process_command_erra(self):
87 """
88 Test ERRA - Authentication Error
89 """
66 # GIVEN: Test object90 # GIVEN: Test object
67 pjlink = pjlink_test91 log_error_calls = [call('(111.111.111.111) PJLINK: {msg}'.format(msg=STATUS_MSG[E_AUTHENTICATION]))]
68 log_text = '(127.0.0.1) Calling function for CLSS'92 log_debug_calls = [call('(111.111.111.111) Processing command "PJLINK" with data "ERRA"')]
69 mock_log.reset_mock()93
70 mock_process_clss = MagicMock()94 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
71 pjlink.pjlink_functions['CLSS'] = mock_process_clss95 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_pjlink') as mock_process_pjlink, \
7296 patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
73 # WHEN: process_command is called with valid function and data97 patch.object(openlp.core.projectors.pjlink.PJLink, 'disconnect_from_host') as mock_disconnect, \
74 pjlink.process_command(cmd='CLSS', data='1')98 patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorAuthentication') as mock_authentication:
7599
76 # THEN: Process method should have been called properly100 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
77 mock_log.debug.assert_called_with(log_text)101
78 mock_process_clss.assert_called_with('1')102 # WHEN: process_command called with ERRA
79103 pjlink.process_command(cmd='PJLINK', data=PJLINK_ERRORS[E_AUTHENTICATION])
80 @patch.object(pjlink_test, 'change_status')104
81 @patch.object(openlp.core.projectors.pjlink, 'log')105 # THEN: Appropriate log entries should have been made and methods called/not called
82 def test_process_command_err1(self, mock_log, mock_change_status):106 assert mock_disconnect.called is True, 'disconnect_from_host should have been called'
107 mock_log.error.assert_has_calls(log_error_calls)
108 mock_log.debug.assert_has_calls(log_debug_calls)
109 mock_change_status.assert_called_once_with(status=E_AUTHENTICATION)
110 mock_authentication.emit.assert_called_once_with(pjlink.name)
111 mock_process_pjlink.assert_not_called()
112
113 def test_process_command_err1(self):
83 """114 """
84 Test ERR1 - Undefined projector function115 Test ERR1 - Undefined projector function
85 """116 """
86 # GIVEN: Test object117 # GIVEN: Test object
87 pjlink = pjlink_test118 log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_UNDEFINED]))]
88 log_text = '(127.0.0.1) Projector returned error "ERR1"'119 log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR1"'),
89 mock_change_status.reset_mock()120 call('(111.111.111.111) Calling function for CLSS')]
90 mock_log.reset_mock()121
91122 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
92 # WHEN: process_command called with ERR1123 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
93 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])124
94125 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
95 # THEN: Error should be logged and status_change should be called126
96 mock_change_status.assert_called_once_with(E_UNDEFINED, 'Undefined Command: "CLSS"')127 # WHEN: process_command called with ERR1
97 mock_log.error.assert_called_with(log_text)128 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
98129
99 @patch.object(pjlink_test, 'change_status')130 # THEN: Appropriate log entries should have been made and methods called
100 @patch.object(openlp.core.projectors.pjlink, 'log')131 mock_log.error.assert_has_calls(log_error_text)
101 def test_process_command_err2(self, mock_log, mock_change_status):132 mock_log.debug.assert_has_calls(log_debug_text)
133 mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNDEFINED])
134
135 def test_process_command_err2(self):
102 """136 """
103 Test ERR2 - Parameter Error137 Test ERR2 - Parameter Error
104 """138 """
105 # GIVEN: Test object139 # GIVEN: Test object
106 pjlink = pjlink_test140 log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_PARAMETER]))]
107 log_text = '(127.0.0.1) Projector returned error "ERR2"'141 log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR2"'),
108 mock_change_status.reset_mock()142 call('(111.111.111.111) Calling function for CLSS')]
109 mock_log.reset_mock()143
110144 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
111 # WHEN: process_command called with ERR2145 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
112 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])146
113147 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
114 # THEN: Error should be logged and status_change should be called148
115 mock_change_status.assert_called_once_with(E_PARAMETER)149 # WHEN: process_command called with ERR2
116 mock_log.error.assert_called_with(log_text)150 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
117151
118 @patch.object(pjlink_test, 'change_status')152 # THEN: Appropriate log entries should have been made and methods called/not called
119 @patch.object(openlp.core.projectors.pjlink, 'log')153 mock_log.error.assert_has_calls(log_error_text)
120 def test_process_command_err3(self, mock_log, mock_change_status):154 mock_log.debug.assert_has_calls(log_debug_text)
121 """155 mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PARAMETER])
122 Test ERR3 - Unavailable error156
123 """157 def test_process_command_err3(self):
124 # GIVEN: Test object158 """
125 pjlink = pjlink_test159 Test ERR3 - Unavailable error
126 log_text = '(127.0.0.1) Projector returned error "ERR3"'160 """
127 mock_change_status.reset_mock()161 # GIVEN: Test object
128 mock_log.reset_mock()162 log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_UNAVAILABLE]))]
129163 log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR3"'),
130 # WHEN: process_command called with ERR3164 call('(111.111.111.111) Calling function for CLSS')]
131 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])165
132166 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
133 # THEN: Error should be logged and status_change should be called167 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
134 mock_change_status.assert_called_once_with(E_UNAVAILABLE)168
135 mock_log.error.assert_called_with(log_text)169 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
136170
137 @patch.object(pjlink_test, 'change_status')171 # WHEN: process_command called with ERR3
138 @patch.object(openlp.core.projectors.pjlink, 'log')172 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
139 def test_process_command_err4(self, mock_log, mock_change_status):173
140 """174 # THEN: Appropriate log entries should have been made and methods called
141 Test ERR3 - Unavailable error175 mock_log.error.assert_has_calls(log_error_text)
142 """176 mock_log.debug.assert_has_calls(log_debug_text)
143 # GIVEN: Test object177 mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNAVAILABLE])
144 pjlink = pjlink_test178
145 log_text = '(127.0.0.1) Projector returned error "ERR4"'179 def test_process_command_err4(self):
146 mock_change_status.reset_mock()180 """
147 mock_log.reset_mock()181 Test ERR3 - Unavailable error
148182 """
149 # WHEN: process_command called with ERR3183 # GIVEN: Test object
150 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])184 log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_PROJECTOR]))]
151185 log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR4"'),
152 # THEN: Error should be logged and status_change should be called186 call('(111.111.111.111) Calling function for CLSS')]
153 mock_change_status.assert_called_once_with(E_PROJECTOR)187
154 mock_log.error.assert_called_with(log_text)188 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
155189 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
156 @patch.object(pjlink_test, 'projectorAuthentication')190
157 @patch.object(pjlink_test, 'change_status')191 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
158 @patch.object(pjlink_test, 'disconnect_from_host')192
159 @patch.object(openlp.core.projectors.pjlink, 'log')193 # WHEN: process_command called with ERR4
160 def test_process_command_erra(self, mock_log, mock_disconnect, mock_change_status, mock_err_authenticate):194 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
161 """195
162 Test ERRA - Authentication Error196 # THEN: Appropriate log entries should have been made and methods called
163 """197 mock_log.error.assert_has_calls(log_error_text)
164 # GIVEN: Test object198 mock_log.debug.assert_has_calls(log_debug_text)
165 pjlink = pjlink_test199 mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PROJECTOR])
166 log_text = '(127.0.0.1) Projector returned error "ERRA"'
167 mock_change_status.reset_mock()
168 mock_log.reset_mock()
169
170 # WHEN: process_command called with ERRA
171 pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_AUTHENTICATION])
172
173 # THEN: Error should be logged and several methods should be called
174 self.assertTrue(mock_disconnect.called, 'disconnect_from_host should have been called')
175 mock_change_status.assert_called_once_with(E_AUTHENTICATION)
176 mock_log.error.assert_called_with(log_text)
177200
178 def test_process_command_future(self):201 def test_process_command_future(self):
179 """202 """
180 Test command valid but no method to process yet203 Test command valid but no method to process yet
181 """204 """
182 # GIVEN: Initial mocks and data
183 mock_log = patch.object(openlp.core.projectors.pjlink, 'log').start()
184 mock_functions = patch.object(self.pjlink_test, 'pjlink_functions').start()
185 mock_functions.return_value = []
186
187 pjlink = self.pjlink_test
188 log_text = '(111.111.111.111) Unable to process command="CLSS" (Future option?)'
189
190 # WHEN: process_command called with an unknown command
191 pjlink.process_command(cmd='CLSS', data='DONT CARE')
192
193 # THEN: Error should be logged and no command called
194 self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')
195 mock_log.warning.assert_called_once_with(log_text)
196
197 @patch.object(pjlink_test, 'pjlink_functions')
198 @patch.object(openlp.core.projectors.pjlink, 'log')
199 def test_process_command_invalid(self, mock_log, mock_functions):
200 """
201 Test not a valid command
202 """
203 # GIVEN: Test object205 # GIVEN: Test object
204 pjlink = pjlink_test206 log_warning_text = [call('(111.111.111.111) Unable to process command="CLSS" (Future option?)')]
205 mock_functions.reset_mock()207 log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "Huh?"')]
206 mock_log.reset_mock()208
207209 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
208 # WHEN: process_command called with an unknown command210 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
209 pjlink.process_command(cmd='Unknown', data='Dont Care')211
210 log_text = '(127.0.0.1) Ignoring command="Unknown" (Invalid/Unknown)'212 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
211213 pjlink.pjlink_functions = MagicMock()
212 # THEN: Error should be logged and no command called214
213 self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')215 # WHEN: Processing a possible future command
214 mock_log.error.assert_called_once_with(log_text)216 pjlink.process_command(cmd='CLSS', data="Huh?")
217
218 # THEN: Appropriate log entries should have been made and methods called/not called
219 mock_log.debug.assert_has_calls(log_debug_text)
220 mock_log.warning.assert_has_calls(log_warning_text)
221 assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions'
222 assert mock_process_clss.called is False, 'Should not have called process_clss'
215223
216 def test_process_command_ok(self):224 def test_process_command_ok(self):
217 """225 """
218 Test command returned success226 Test command returned success
219 """227 """
220 # GIVEN: Initial mocks and data228 # GIVEN: Initial mocks and data
221 mock_log = patch.object(openlp.core.projectors.pjlink, 'log').start()229 # GIVEN: Test object and mocks
222 mock_send_command = patch.object(self.pjlink_test, 'send_command').start()230 log_debug_calls = [call('(111.111.111.111) Processing command "CLSS" with data "OK"'),
223231 call('(111.111.111.111) Command "CLSS" returned OK')]
224 pjlink = self.pjlink_test232
225 log_text = '(111.111.111.111) Command "POWR" returned OK'233 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
226234 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
227 # WHEN: process_command called with a command that returns OK235 patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
228 pjlink.process_command(cmd='POWR', data='OK')236
229237 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
230 # THEN: Appropriate calls should have been made238
231 mock_log.debug.assert_called_with(log_text)239 # WHEN: process_command is called with valid function and data
232 mock_send_command.assert_called_once_with(cmd='POWR')240 pjlink.process_command(cmd='CLSS', data='OK')
241
242 # THEN: Appropriate log entries should have been made and methods called
243 mock_log.debug.assert_has_calls(log_debug_calls)
244 mock_send_command.assert_called_once_with(cmd='CLSS')
245 mock_process_clss.assert_not_called()
233246
=== modified file 'tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py'
--- tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py 2017-12-28 08:22:55 +0000
+++ tests/functional/openlp_core/projectors/test_projector_pjlink_commands_01.py 2018-01-03 05:54:24 +0000
@@ -23,937 +23,1017 @@
23Package to test the openlp.core.projectors.pjlink commands package.23Package to test the openlp.core.projectors.pjlink commands package.
24"""24"""
25from unittest import TestCase25from unittest import TestCase
26from unittest.mock import patch26from unittest.mock import call, patch
2727
28import openlp.core.projectors.pjlink28import openlp.core.projectors.pjlink
29from openlp.core.projectors.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \29from openlp.core.projectors.constants import PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_POWR_STATUS, \
30 PJLINK_POWR_STATUS, \30 STATUS_CODE, STATUS_MSG, E_ERROR, E_NOT_CONNECTED, E_UNKNOWN_SOCKET_ERROR, E_WARN, \
31 E_ERROR, E_NOT_CONNECTED, E_SOCKET_ADDRESS_NOT_AVAILABLE, E_UNKNOWN_SOCKET_ERROR, E_WARN, \31 S_CONNECTED, S_CONNECTING, S_OFF, S_OK, S_ON, S_NOT_CONNECTED, S_STANDBY
32 S_CONNECTED, S_OFF, S_ON, S_NOT_CONNECTED, S_CONNECTING, S_STANDBY
33from openlp.core.projectors.db import Projector32from openlp.core.projectors.db import Projector
34from openlp.core.projectors.pjlink import PJLink33from openlp.core.projectors.pjlink import PJLink
35from tests.resources.projector.data import TEST_PIN, TEST1_DATA34
3635from tests.resources.projector.data import TEST1_DATA
37pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
38pjlink_test.ip = '127.0.0.1'
39
40# Create a list of ERST positional data so we don't have to redo the same buildup multiple times
41PJLINK_ERST_POSITIONS = []
42for pos in range(0, len(PJLINK_ERST_DATA)):
43 if pos in PJLINK_ERST_DATA:
44 PJLINK_ERST_POSITIONS.append(PJLINK_ERST_DATA[pos])
4536
4637
47class TestPJLinkCommands(TestCase):38class TestPJLinkCommands(TestCase):
48 """39 """
49 Tests for the PJLinkCommands class part 140 Tests for the PJLinkCommands class part 1
50 """41 """
51 @patch.object(pjlink_test, 'changeStatus')42 def test_projector_change_status_unknown_socket_error(self):
52 @patch.object(openlp.core.projectors.pjlink, 'log')
53 def test_projector_change_status_connection_error(self, mock_log, mock_change_status):
54 """43 """
55 Test change_status with connection error44 Test change_status with connection error
56 """45 """
57 # GIVEN: Test object46 log_debug_calls = [
58 pjlink = pjlink_test47 call('(111.111.111.111) Changing status to '
59 pjlink.projector_status = 048 '{status} "{msg}"'.format(status=STATUS_CODE[E_UNKNOWN_SOCKET_ERROR],
60 pjlink.status_connect = 049 msg=STATUS_MSG[E_UNKNOWN_SOCKET_ERROR])),
61 test_code = E_UNKNOWN_SOCKET_ERROR50 call('(111.111.111.111) status_connect: '
62 mock_change_status.reset_mock()51 '{code}: "{msg}"'.format(code=STATUS_CODE[E_NOT_CONNECTED],
63 mock_log.reset_mock()52 msg=STATUS_MSG[E_NOT_CONNECTED])),
6453 call('(111.111.111.111) projector_status: '
65 # WHEN: change_status called with unknown socket error54 '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
66 pjlink.change_status(status=test_code, msg=None)55 msg=STATUS_MSG[S_OK])),
6756 call('(111.111.111.111) error_status: '
68 # THEN: Proper settings should change and signals sent57 '{code}: "{msg}"'.format(code=STATUS_CODE[E_UNKNOWN_SOCKET_ERROR],
69 self.assertEqual(pjlink.projector_status, E_NOT_CONNECTED, 'Projector status should be NOT CONNECTED')58 msg=STATUS_MSG[E_UNKNOWN_SOCKET_ERROR]))]
70 self.assertEqual(pjlink.status_connect, E_NOT_CONNECTED, 'Status connect should be NOT CONNECTED')59
71 mock_change_status.emit.assert_called_once_with(pjlink.ip, E_UNKNOWN_SOCKET_ERROR,60 # GIVEN: Test object and mocks
72 'An unidentified error occurred')61 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
73 self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')62 patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus, \
7463 patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
75 @patch.object(pjlink_test, 'changeStatus')64
76 @patch.object(openlp.core.projectors.pjlink, 'log')65 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
77 def test_projector_change_status_connection_status_connecting(self, mock_log, mock_change_status):66 pjlink.projector_status = 0
78 """67 pjlink.status_connect = 0
79 Test change_status with connection status68
80 """69 # WHEN: change_status called with unknown socket error
81 # GIVEN: Test object70 pjlink.change_status(status=E_UNKNOWN_SOCKET_ERROR)
82 pjlink = pjlink_test71
83 pjlink.projector_status = 072 # THEN: Proper settings should change and signals sent
84 pjlink.status_connect = 073 mock_log.debug.assert_has_calls(log_debug_calls)
85 test_code = S_CONNECTING74 assert pjlink.projector_status == S_OK, 'Projector status should not have changed'
86 mock_change_status.reset_mock()75 assert pjlink.status_connect == E_NOT_CONNECTED, 'Status connect should be NOT CONNECTED'
87 mock_log.reset_mock()76 assert mock_UpdateIcons.emit.called is True, 'Should have called UpdateIcons'
8877 mock_changeStatus.emit.assert_called_once_with(pjlink.ip, E_UNKNOWN_SOCKET_ERROR,
89 # WHEN: change_status called with unknown socket error78 STATUS_MSG[E_UNKNOWN_SOCKET_ERROR])
90 pjlink.change_status(status=test_code, msg=None)79
9180 def test_projector_change_status_connection_status_connecting(self):
92 # THEN: Proper settings should change and signals sent81 """
93 self.assertEqual(pjlink.projector_status, S_NOT_CONNECTED, 'Projector status should be NOT CONNECTED')82 Test change_status with connecting status
94 self.assertEqual(pjlink.status_connect, S_CONNECTING, 'Status connect should be CONNECTING')83 """
95 mock_change_status.emit.assert_called_once_with(pjlink.ip, S_CONNECTING, 'Connecting')84 log_debug_calls = [
96 self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')85 call('(111.111.111.111) Changing status to '
9786 '{status} "{msg}"'.format(status=STATUS_CODE[S_CONNECTING],
98 @patch.object(pjlink_test, 'changeStatus')87 msg=STATUS_MSG[S_CONNECTING])),
99 @patch.object(openlp.core.projectors.pjlink, 'log')88 call('(111.111.111.111) status_connect: '
100 def test_projector_change_status_connection_status_connected(self, mock_log, mock_change_status):89 '{code}: "{msg}"'.format(code=STATUS_CODE[S_CONNECTING],
101 """90 msg=STATUS_MSG[S_CONNECTING])),
102 Test change_status with connection status91 call('(111.111.111.111) projector_status: '
103 """92 '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
104 # GIVEN: Test object93 msg=STATUS_MSG[S_OK])),
105 pjlink = pjlink_test94 call('(111.111.111.111) error_status: '
106 pjlink.projector_status = 095 '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
107 pjlink.status_connect = 096 msg=STATUS_MSG[S_OK]))]
108 test_code = S_ON97
109 mock_change_status.reset_mock()98 # GIVEN: Test object and mocks
110 mock_log.reset_mock()99 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
111100 patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus, \
112 # WHEN: change_status called with unknown socket error101 patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
113 pjlink.change_status(status=test_code, msg=None)102
114103 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
115 # THEN: Proper settings should change and signals sent104 pjlink.projector_status = 0
116 self.assertEqual(pjlink.projector_status, S_ON, 'Projector status should be ON')105 pjlink.status_connect = 0
117 self.assertEqual(pjlink.status_connect, S_CONNECTED, 'Status connect should be CONNECTED')106
118 mock_change_status.emit.assert_called_once_with(pjlink.ip, S_ON, 'Power is on')107 # WHEN: change_status called with CONNECTING
119 self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')108 pjlink.change_status(status=S_CONNECTING)
120109
121 @patch.object(pjlink_test, 'changeStatus')110 # THEN: Proper settings should change and signals sent
122 @patch.object(openlp.core.projectors.pjlink, 'log')111 mock_log.debug.assert_has_calls(log_debug_calls)
123 def test_projector_change_status_connection_status_with_message(self, mock_log, mock_change_status):112 mock_changeStatus.emit.assert_called_once_with(pjlink.ip, S_CONNECTING, STATUS_MSG[S_CONNECTING])
124 """113 assert pjlink.projector_status == S_OK, 'Projector status should not have changed'
125 Test change_status with connection status114 assert pjlink.status_connect == S_CONNECTING, 'Status connect should be CONNECTING'
126 """115 assert mock_UpdateIcons.emit.called is True, 'Should have called UpdateIcons'
127 # GIVEN: Test object116
128 pjlink = pjlink_test117 def test_projector_change_status_connection_status_connected(self):
129 pjlink.projector_status = 0118 """
130 pjlink.status_connect = 0119 Test change_status with connected status
120 """
121 log_debug_calls = [
122 call('(111.111.111.111) Changing status to '
123 '{status} "{msg}"'.format(status=STATUS_CODE[S_CONNECTED],
124 msg=STATUS_MSG[S_CONNECTED])),
125 call('(111.111.111.111) status_connect: '
126 '{code}: "{msg}"'.format(code=STATUS_CODE[S_CONNECTED],
127 msg=STATUS_MSG[S_CONNECTED])),
128 call('(111.111.111.111) projector_status: '
129 '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
130 msg=STATUS_MSG[S_OK])),
131 call('(111.111.111.111) error_status: '
132 '{code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
133 msg=STATUS_MSG[S_OK]))]
134
135 # GIVEN: Test object and mocks
136 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
137 patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus:
138
139 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
140 pjlink.projector_status = 0
141 pjlink.status_connect = 0
142
143 # WHEN: change_status called with CONNECTED
144 pjlink.change_status(status=S_CONNECTED)
145
146 # THEN: Proper settings should change and signals sent
147 mock_log.debug.assert_has_calls(log_debug_calls)
148 mock_changeStatus.emit.assert_called_once_with(pjlink.ip, S_CONNECTED, 'Connected')
149 assert pjlink.projector_status == S_OK, 'Projector status should not have changed'
150 assert pjlink.status_connect == S_CONNECTED, 'Status connect should be CONNECTED'
151
152 def test_projector_change_status_connection_status_with_message(self):
153 """
154 Test change_status with connection status
155 """
131 test_message = 'Different Status Message than default'156 test_message = 'Different Status Message than default'
132 test_code = S_ON157 log_debug_calls = [
133 mock_change_status.reset_mock()158 call('(111.111.111.111) Changing status to {status} "{msg}"'.format(status=STATUS_CODE[S_ON],
134 mock_log.reset_mock()159 msg=test_message)),
135160 call('(111.111.111.111) status_connect: {code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
136 # WHEN: change_status called with unknown socket error161 msg=test_message)),
137 pjlink.change_status(status=test_code, msg=test_message)162 call('(111.111.111.111) projector_status: {code}: "{msg}"'.format(code=STATUS_CODE[S_ON],
138163 msg=test_message)),
139 # THEN: Proper settings should change and signals sent164 call('(111.111.111.111) error_status: {code}: "{msg}"'.format(code=STATUS_CODE[S_OK],
140 self.assertEqual(pjlink.projector_status, S_ON, 'Projector status should be ON')165 msg=test_message))]
141 self.assertEqual(pjlink.status_connect, S_CONNECTED, 'Status connect should be CONNECTED')166
142 mock_change_status.emit.assert_called_once_with(pjlink.ip, S_ON, test_message)167 # GIVEN: Test object and mocks
143 self.assertEqual(mock_log.debug.call_count, 3, 'Debug log should have been called 3 times')168 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
144169 patch.object(openlp.core.projectors.pjlink.PJLink, 'changeStatus') as mock_changeStatus:
145 @patch.object(pjlink_test, 'send_command')170
146 @patch.object(openlp.core.projectors.pjlink, 'log')171 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
147 def test_projector_get_av_mute_status(self, mock_log, mock_send_command):172 pjlink.projector_status = 0
173 pjlink.status_connect = 0
174
175 # WHEN: change_status called with projector ON status
176 pjlink.change_status(status=S_ON, msg=test_message)
177
178 # THEN: Proper settings should change and signals sent
179 mock_log.debug.assert_has_calls(log_debug_calls)
180 mock_changeStatus.emit.assert_called_once_with(pjlink.ip, S_ON, test_message)
181 assert pjlink.projector_status == S_ON, 'Projector status should be ON'
182 assert pjlink.status_connect == S_OK, 'Status connect should not have changed'
183
184 def test_projector_get_av_mute_status(self):
148 """185 """
149 Test sending command to retrieve shutter/audio state186 Test sending command to retrieve shutter/audio state
150 """187 """
151 # GIVEN: Test object
152 pjlink = pjlink_test
153 mock_log.reset_mock()
154 mock_send_command.reset_mock()
155 test_data = 'AVMT'188 test_data = 'AVMT'
156 test_log = '(127.0.0.1) Sending AVMT command'189 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
157190 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
158 # WHEN: get_av_mute_status is called191 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
159 pjlink.get_av_mute_status()192
160193 # GIVEN: Test object and mocks
161 # THEN: log data and send_command should have been called194 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
162 mock_log.debug.assert_called_once_with(test_log)195 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
163 mock_send_command.assert_called_once_with(cmd=test_data)196 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
164197
165 @patch.object(pjlink_test, 'send_command')198 # WHEN: get_av_mute_status is called
166 @patch.object(openlp.core.projectors.pjlink, 'log')199 pjlink.get_av_mute_status()
167 def test_projector_get_available_inputs(self, mock_log, mock_send_command):200
201 # THEN: log data and send_command should have been called
202 mock_log.debug.assert_has_calls(log_debug_calls)
203 mock_send_command.assert_called_once_with(cmd=test_data)
204
205 def test_projector_get_available_inputs(self):
168 """206 """
169 Test sending command to retrieve avaliable inputs207 Test sending command to retrieve avaliable inputs
170 """208 """
171 # GIVEN: Test object
172 pjlink = pjlink_test
173 mock_log.reset_mock()
174 mock_send_command.reset_mock()
175 test_data = 'INST'209 test_data = 'INST'
176 test_log = '(127.0.0.1) Sending INST command'210 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
177211 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
178 # WHEN: get_available_inputs is called212 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
179 pjlink.get_available_inputs()213
180214 # GIVEN: Test object and mocks
181 # THEN: log data and send_command should have been called215 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
182 mock_log.debug.assert_called_once_with(test_log)216 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
183 mock_send_command.assert_called_once_with(cmd=test_data)217 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
184218
185 @patch.object(pjlink_test, 'send_command')219 # WHEN: get_available_inputs is called
186 @patch.object(openlp.core.projectors.pjlink, 'log')220 pjlink.get_available_inputs()
187 def test_projector_get_error_status(self, mock_log, mock_send_command):221
222 # THEN: log data and send_command should have been called
223 mock_log.debug.assert_has_calls(log_debug_calls)
224 mock_send_command.assert_called_once_with(cmd=test_data)
225
226 def test_projector_get_error_status(self):
188 """227 """
189 Test sending command to retrieve projector error status228 Test sending command to retrieve projector error status
190 """229 """
191 # GIVEN: Test object
192 pjlink = pjlink_test
193 mock_log.reset_mock()
194 mock_send_command.reset_mock()
195 test_data = 'ERST'230 test_data = 'ERST'
196 test_log = '(127.0.0.1) Sending ERST command'231 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
197232 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
198 # WHEN: get_error_status is called233 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
199 pjlink.get_error_status()234 # GIVEN: Test object and mocks
200235 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
201 # THEN: log data and send_command should have been called236 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
202 mock_log.debug.assert_called_once_with(test_log)237 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
203 mock_send_command.assert_called_once_with(cmd=test_data)238
204239 # WHEN: get_error_status is called
205 @patch.object(pjlink_test, 'send_command')240 pjlink.get_error_status()
206 @patch.object(openlp.core.projectors.pjlink, 'log')241
207 def test_projector_get_input_source(self, mock_log, mock_send_command):242 # THEN: log data and send_command should have been called
243 mock_log.debug.assert_has_calls(log_debug_calls)
244 mock_send_command.assert_called_once_with(cmd=test_data)
245
246 def test_projector_get_input_source(self):
208 """247 """
209 Test sending command to retrieve current input248 Test sending command to retrieve current input
210 """249 """
211 # GIVEN: Test object
212 pjlink = pjlink_test
213 mock_log.reset_mock()
214 mock_send_command.reset_mock()
215 test_data = 'INPT'250 test_data = 'INPT'
216 test_log = '(127.0.0.1) Sending INPT command'251 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
217252 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
218 # WHEN: get_input_source is called253 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
219 pjlink.get_input_source()254
220255 # GIVEN: Test object and mocks
221 # THEN: log data and send_command should have been called256 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
222 mock_log.debug.assert_called_once_with(test_log)257 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
223 mock_send_command.assert_called_once_with(cmd=test_data)258 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
224259
225 @patch.object(pjlink_test, 'send_command')260 # WHEN: get_input_source is called
226 @patch.object(openlp.core.projectors.pjlink, 'log')261 pjlink.get_input_source()
227 def test_projector_get_lamp_status(self, mock_log, mock_send_command):262
263 # THEN: log data and send_command should have been called
264 mock_log.debug.assert_has_calls(log_debug_calls)
265 mock_send_command.assert_called_once_with(cmd=test_data)
266
267 def test_projector_get_lamp_status(self):
228 """268 """
229 Test sending command to retrieve lamp(s) status269 Test sending command to retrieve lamp(s) status
230 """270 """
231 # GIVEN: Test object
232 pjlink = pjlink_test
233 mock_log.reset_mock()
234 mock_send_command.reset_mock()
235 test_data = 'LAMP'271 test_data = 'LAMP'
236 test_log = '(127.0.0.1) Sending LAMP command'272 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
237273 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
238 # WHEN: get_lamp_status is called274 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
239 pjlink.get_lamp_status()275
240276 # GIVEN: Test object and mocks
241 # THEN: log data and send_command should have been called277 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
242 mock_log.debug.assert_called_once_with(test_log)278 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
243 mock_send_command.assert_called_once_with(cmd=test_data)279 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
244280
245 @patch.object(pjlink_test, 'send_command')281 # WHEN: get_input_source is called
246 @patch.object(openlp.core.projectors.pjlink, 'log')282 pjlink.get_lamp_status()
247 def test_projector_get_manufacturer(self, mock_log, mock_send_command):283
284 # THEN: log data and send_command should have been called
285 mock_log.debug.assert_has_calls(log_debug_calls)
286 mock_send_command.assert_called_once_with(cmd=test_data)
287
288 def test_projector_get_manufacturer(self):
248 """289 """
249 Test sending command to retrieve manufacturer name290 Test sending command to retrieve manufacturer name
250 """291 """
251 # GIVEN: Test object
252 pjlink = pjlink_test
253 mock_log.reset_mock()
254 mock_send_command.reset_mock()
255 test_data = 'INF1'292 test_data = 'INF1'
256 test_log = '(127.0.0.1) Sending INF1 command'293 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
257294 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
258 # WHEN: get_manufacturer is called295 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
259 pjlink.get_manufacturer()296
260297 # GIVEN: Test object and mocks
261 # THEN: log data and send_command should have been called298 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
262 mock_log.debug.assert_called_once_with(test_log)299 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
263 mock_send_command.assert_called_once_with(cmd=test_data)300 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
264301
265 @patch.object(pjlink_test, 'send_command')302 # WHEN: get_input_source is called
266 @patch.object(openlp.core.projectors.pjlink, 'log')303 pjlink.get_manufacturer()
267 def test_projector_get_model(self, mock_log, mock_send_command):304
305 # THEN: log data and send_command should have been called
306 mock_log.debug.assert_has_calls(log_debug_calls)
307 mock_send_command.assert_called_once_with(cmd=test_data)
308
309 def test_projector_get_model(self):
268 """310 """
269 Test sending command to get model information311 Test sending command to get model information
270 """312 """
271 # GIVEN: Test object
272 pjlink = pjlink_test
273 mock_log.reset_mock()
274 mock_send_command.reset_mock()
275 test_data = 'INF2'313 test_data = 'INF2'
276 test_log = '(127.0.0.1) Sending INF2 command'314 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
277315 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
278 # WHEN: get_model is called316 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
279 pjlink.get_model()317
280318 # GIVEN: Test object and mocks
281 # THEN: log data and send_command should have been called319 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
282 mock_log.debug.assert_called_once_with(test_log)320 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
283 mock_send_command.assert_called_once_with(cmd=test_data)321 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
284322
285 @patch.object(pjlink_test, 'send_command')323 # WHEN: get_input_source is called
286 @patch.object(openlp.core.projectors.pjlink, 'log')324 pjlink.get_model()
287 def test_projector_get_name(self, mock_log, mock_send_command):325
326 # THEN: log data and send_command should have been called
327 mock_log.debug.assert_has_calls(log_debug_calls)
328 mock_send_command.assert_called_once_with(cmd=test_data)
329
330 def test_projector_get_name(self):
288 """331 """
289 Test sending command to get user-assigned name332 Test sending command to get user-assigned name
290 """333 """
291 # GIVEN: Test object
292 pjlink = pjlink_test
293 mock_log.reset_mock()
294 mock_send_command.reset_mock()
295 test_data = 'NAME'334 test_data = 'NAME'
296 test_log = '(127.0.0.1) Sending NAME command'335 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
297336 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
298 # WHEN: get_name is called337 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
299 pjlink.get_name()338
300339 # GIVEN: Test object and mocks
301 # THEN: log data and send_command should have been called340 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
302 mock_log.debug.assert_called_once_with(test_log)341 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
303 mock_send_command.assert_called_once_with(cmd=test_data)342 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
304343
305 @patch.object(pjlink_test, 'send_command')344 # WHEN: get_input_source is called
306 @patch.object(openlp.core.projectors.pjlink, 'log')345 pjlink.get_name()
307 def test_projector_get_other_info(self, mock_log, mock_send_command):346
347 # THEN: log data and send_command should have been called
348 mock_log.debug.assert_has_calls(log_debug_calls)
349 mock_send_command.assert_called_once_with(cmd=test_data)
350
351 def test_projector_get_other_info(self):
308 """352 """
309 Test sending command to retrieve other information353 Test sending command to retrieve other information
310 """354 """
311 # GIVEN: Test object
312 pjlink = pjlink_test
313 mock_log.reset_mock()
314 mock_send_command.reset_mock()
315 test_data = 'INFO'355 test_data = 'INFO'
316 test_log = '(127.0.0.1) Sending INFO command'356 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
317357 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
318 # WHEN: get_other_info is called358 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
319 pjlink.get_other_info()359
320360 # GIVEN: Test object and mocks
321 # THEN: log data and send_command should have been called361 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
322 mock_log.debug.assert_called_once_with(test_log)362 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
323 mock_send_command.assert_called_once_with(cmd=test_data)363 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
324364
325 @patch.object(pjlink_test, 'send_command')365 # WHEN: get_input_source is called
326 @patch.object(openlp.core.projectors.pjlink, 'log')366 pjlink.get_other_info()
327 def test_projector_get_power_status(self, mock_log, mock_send_command):367
368 # THEN: log data and send_command should have been called
369 mock_log.debug.assert_has_calls(log_debug_calls)
370 mock_send_command.assert_called_once_with(cmd=test_data)
371
372 def test_projector_get_power_status(self):
328 """373 """
329 Test sending command to retrieve current power state374 Test sending command to retrieve current power state
330 """375 """
331 # GIVEN: Test object
332 pjlink = pjlink_test
333 mock_log.reset_mock()
334 mock_send_command.reset_mock()
335 test_data = 'POWR'376 test_data = 'POWR'
336 test_log = '(127.0.0.1) Sending POWR command'377 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
337378 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
338 # WHEN: get_power_status called379 call('(111.111.111.111) Sending {cmd} command'.format(cmd=test_data))]
339 pjlink.get_power_status()380
340381 # GIVEN: Test object and mocks
341 # THEN: log data and send_command should have been called382 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
342 mock_log.debug.assert_called_once_with(test_log)383 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command:
343 mock_send_command.assert_called_once_with(cmd=test_data)384 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
344385
345 def test_projector_get_status_error(self):386 # WHEN: get_input_source is called
346 """387 pjlink.get_power_status()
347 Test to check returned information for error code388
348 """389 # THEN: log data and send_command should have been called
349 # GIVEN: Test object390 mock_log.debug.assert_has_calls(log_debug_calls)
350 pjlink = pjlink_test391 mock_send_command.assert_called_once_with(cmd=test_data)
351 test_string = 'E_SOCKET_ADDRESS_NOT_AVAILABLE'
352 test_message = 'The address specified to socket.bind() does not belong to the host'
353
354 # WHEN: get_status called
355 string, message = pjlink._get_status(status=E_SOCKET_ADDRESS_NOT_AVAILABLE)
356
357 # THEN: Proper strings should have been returned
358 self.assertEqual(string, test_string, 'Code as string should have been returned')
359 self.assertEqual(message, test_message, 'Description of code should have been returned')
360392
361 def test_projector_get_status_invalid(self):393 def test_projector_get_status_invalid(self):
362 """394 """
363 Test to check returned information for error code395 Test to check returned information for error code
364 """396 """
365 # GIVEN: Test object397 # GIVEN: Test object
366 pjlink = pjlink_test398 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
367 test_string = 'Test string since get_status will only work with int'399 test_string = 'NaN test'
368 test_message = 'Invalid status code'
369400
370 # WHEN: get_status called401 # WHEN: get_status called
371 string, message = pjlink._get_status(status=test_string)402 code, message = pjlink._get_status(status=test_string)
372403
373 # THEN: Proper strings should have been returned404 # THEN: Proper data should have been returned
374 self.assertEqual(string, -1, 'Should have returned -1 as a bad status check')405 assert code == -1, 'Should have returned -1 as a bad status check'
375 self.assertEqual(message, test_message, 'Error message should have been returned')406 assert message is None, 'Invalid code type should have returned None for message'
376407
377 def test_projector_get_status_status(self):408 def test_projector_get_status_valid(self):
378 """409 """
379 Test to check returned information for status codes410 Test to check returned information for status codes
380 """411 """
381 # GIVEN: Test object412 # GIVEN: Test object
382 pjlink = pjlink_test413 test_message = 'Not Connected'
383 test_string = 'S_NOT_CONNECTED'414 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
384 test_message = 'Not connected'
385415
386 # WHEN: get_status called416 # WHEN: get_status called
387 string, message = pjlink._get_status(status=S_NOT_CONNECTED)417 code, message = pjlink._get_status(status=S_NOT_CONNECTED)
388418
389 # THEN: Proper strings should have been returned419 # THEN: Proper strings should have been returned
390 self.assertEqual(string, test_string, 'Code as string should have been returned')420 assert code == 'S_NOT_CONNECTED', 'Code returned should have been the same code that was sent'
391 self.assertEqual(message, test_message, 'Description of code should have been returned')421 assert message == test_message, 'Description of code should have been returned'
392422
393 def test_projector_get_status_unknown(self):423 def test_projector_get_status_unknown(self):
394 """424 """
395 Test to check returned information for unknown code425 Test to check returned information for unknown code
396 """426 """
397 # GIVEN: Test object427 # GIVEN: Test object
398 pjlink = pjlink_test428 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
399 test_string = 999999
400 test_message = 'Unknown status'
401429
402 # WHEN: get_status called430 # WHEN: get_status called
403 string, message = pjlink._get_status(status=test_string)431 code, message = pjlink._get_status(status=9999)
404432
405 # THEN: Proper strings should have been returned433 # THEN: Proper strings should have been returned
406 self.assertEqual(string, test_string, 'Received code should have been returned')434 assert code is None, 'Code returned should have been the same code that was sent'
407 self.assertEqual(message, test_message, 'Unknown status string should have been returned')435 assert message is None, 'Should have returned None as message'
408436
409 def test_projector_process_inf1(self):437 def test_projector_process_inf1(self):
410 """438 """
411 Test saving INF1 data (manufacturer)439 Test saving INF1 data (manufacturer)
412 """440 """
441 test_data = 'TEst INformation MultiCase'
442
413 # GIVEN: Test object443 # GIVEN: Test object
414 pjlink = pjlink_test444 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
415 pjlink.manufacturer = None445 pjlink.manufacturer = None
416 test_data = 'TEst INformation MultiCase'
417446
418 # WHEN: process_inf called with test data447 # WHEN: process_inf called with test data
419 pjlink.process_inf1(data=test_data)448 pjlink.process_inf1(data=test_data)
420449
421 # THEN: Data should be saved450 # THEN: Data should be saved
422 self.assertEqual(pjlink.manufacturer, test_data, 'Test data should have been saved')451 assert pjlink.manufacturer == test_data, 'Test data should have been saved'
423452
424 def test_projector_process_inf2(self):453 def test_projector_process_inf2(self):
425 """454 """
426 Test saving INF2 data (model)455 Test saving INF2 data (model)
427 """456 """
457 test_data = 'TEst moDEl MultiCase'
458
428 # GIVEN: Test object459 # GIVEN: Test object
429 pjlink = pjlink_test460 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
430 pjlink.model = None461 pjlink.model = None
431 test_data = 'TEst moDEl MultiCase'
432462
433 # WHEN: process_inf called with test data463 # WHEN: process_inf called with test data
434 pjlink.process_inf2(data=test_data)464 pjlink.process_inf2(data=test_data)
435465
436 # THEN: Data should be saved466 # THEN: Data should be saved
437 self.assertEqual(pjlink.model, test_data, 'Test data should have been saved')467 assert pjlink.model == test_data, 'Test data should have been saved'
438468
439 def test_projector_process_info(self):469 def test_projector_process_info(self):
440 """470 """
441 Test saving INFO data (other information)471 Test saving INFO data (other information)
442 """472 """
473 test_data = 'TEst ExtrANEous MultiCase INformatoin that MFGR might Set'
474
443 # GIVEN: Test object475 # GIVEN: Test object
444 pjlink = pjlink_test476 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
445 pjlink.other_info = None477 pjlink.other_info = None
446 test_data = 'TEst ExtrANEous MultiCase INformatoin that MFGR might Set'
447478
448 # WHEN: process_inf called with test data479 # WHEN: process_inf called with test data
449 pjlink.process_info(data=test_data)480 pjlink.process_info(data=test_data)
450481
451 # THEN: Data should be saved482 # THEN: Data should be saved
452 self.assertEqual(pjlink.other_info, test_data, 'Test data should have been saved')483 assert pjlink.other_info == test_data, 'Test data should have been saved'
453484
454 @patch.object(pjlink_test, 'projectorUpdateIcons')485 def test_projector_process_avmt_bad_data(self):
455 def test_projector_process_avmt_bad_data(self, mock_UpdateIcons):
456 """486 """
457 Test avmt bad data fail487 Test avmt bad data fail
458 """488 """
459 # GIVEN: Test object489 # GIVEN: Test object
460 pjlink = pjlink_test490 with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
461 pjlink.shutter = True491 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
462 pjlink.mute = True492 pjlink.shutter = True
463493 pjlink.mute = True
464 # WHEN: Called with an invalid setting494
465 pjlink.process_avmt('36')495 # WHEN: Called with an invalid setting
466496 pjlink.process_avmt('36')
467 # THEN: Shutter should be closed and mute should be True497
468 self.assertTrue(pjlink.shutter, 'Shutter should changed')498 # THEN: Shutter should be closed and mute should be True
469 self.assertTrue(pjlink.mute, 'Audio should not have changed')499 assert pjlink.shutter is True, 'Shutter should changed'
470 self.assertFalse(mock_UpdateIcons.emit.called, 'Update icons should NOT have been called')500 assert pjlink.mute is True, 'Audio should not have changed'
471501 assert mock_UpdateIcons.emit.called is False, 'Update icons should NOT have been called'
472 @patch.object(pjlink_test, 'projectorUpdateIcons')502
473 def test_projector_process_avmt_closed_muted(self, mock_UpdateIcons):503 def test_projector_process_avmt_closed_muted(self):
474 """504 """
475 Test avmt status shutter closed and mute off505 Test avmt status shutter closed and mute off
476 """506 """
477 # GIVEN: Test object507 # GIVEN: Test object
478 pjlink = pjlink_test508 with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
479 pjlink.shutter = False509 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
480 pjlink.mute = False510 pjlink.shutter = False
481511 pjlink.mute = False
482 # WHEN: Called with setting shutter to closed and mute on512
483 pjlink.process_avmt('31')513 # WHEN: Called with setting shutter to closed and mute on
484514 pjlink.process_avmt('31')
485 # THEN: Shutter should be closed and mute should be True515
486 self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')516 # THEN: Shutter should be closed and mute should be True
487 self.assertTrue(pjlink.mute, 'Audio should be muted')517 assert pjlink.shutter is True, 'Shutter should have been set to closed'
488 self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')518 assert pjlink.mute is True, 'Audio should be muted'
489519 assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
490 @patch.object(pjlink_test, 'projectorUpdateIcons')520
491 def test_projector_process_avmt_shutter_closed(self, mock_UpdateIcons):521 def test_projector_process_avmt_shutter_closed(self):
492 """522 """
493 Test avmt status shutter closed and audio unchanged523 Test avmt status shutter closed and audio unchanged
494 """524 """
495 # GIVEN: Test object525 # GIVEN: Test object
496 pjlink = pjlink_test526 with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
497 pjlink.shutter = False527 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
498 pjlink.mute = True528 pjlink.shutter = False
499529 pjlink.mute = True
500 # WHEN: Called with setting shutter closed and mute off530
501 pjlink.process_avmt('11')531 # WHEN: Called with setting shutter closed and mute off
502532 pjlink.process_avmt('11')
503 # THEN: Shutter should be True and mute should be False533
504 self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')534 # THEN: Shutter should be True and mute should be False
505 self.assertTrue(pjlink.mute, 'Audio should not have changed')535 assert pjlink.shutter is True, 'Shutter should have been set to closed'
506 self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')536 assert pjlink.mute is True, 'Audio should not have changed'
507537 assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
508 @patch.object(pjlink_test, 'projectorUpdateIcons')538
509 def test_projector_process_avmt_audio_muted(self, mock_UpdateIcons):539 def test_projector_process_avmt_audio_muted(self):
510 """540 """
511 Test avmt status shutter unchanged and mute on541 Test avmt status shutter unchanged and mute on
512 """542 """
513 # GIVEN: Test object543 # GIVEN: Test object
514 pjlink = pjlink_test544 with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
515 pjlink.shutter = True545 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
516 pjlink.mute = False546 pjlink.shutter = True
517547 pjlink.mute = False
518 # WHEN: Called with setting shutter closed and mute on548
519 pjlink.process_avmt('21')549 # WHEN: Called with setting shutter closed and mute on
520550 pjlink.process_avmt('21')
521 # THEN: Shutter should be closed and mute should be True551
522 self.assertTrue(pjlink.shutter, 'Shutter should not have changed')552 # THEN: Shutter should be closed and mute should be True
523 self.assertTrue(pjlink.mute, 'Audio should be off')553 assert pjlink.shutter is True, 'Shutter should not have changed'
524 self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')554 assert pjlink.mute is True, 'Audio should be off'
525555 assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
526 @patch.object(pjlink_test, 'projectorUpdateIcons')556
527 def test_projector_process_avmt_open_unmuted(self, mock_UpdateIcons):557 def test_projector_process_avmt_open_unmuted(self):
528 """558 """
529 Test avmt status shutter open and mute off559 Test avmt status shutter open and mute off
530 """560 """
531 # GIVEN: Test object561 # GIVEN: Test object
532 pjlink = pjlink_test562 with patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
533 pjlink.shutter = True563 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
534 pjlink.mute = True564 pjlink.shutter = True
535565 pjlink.mute = True
536 # WHEN: Called with setting shutter to closed and mute on566
537 pjlink.process_avmt('30')567 # WHEN: Called with setting shutter to closed and mute on
538568 pjlink.process_avmt('30')
539 # THEN: Shutter should be closed and mute should be True569
540 self.assertFalse(pjlink.shutter, 'Shutter should have been set to open')570 # THEN: Shutter should be closed and mute should be True
541 self.assertFalse(pjlink.mute, 'Audio should be on')571 assert pjlink.shutter is False, 'Shutter should have been set to open'
542 self.assertTrue(mock_UpdateIcons.emit.called, 'Update icons should have been called')572 assert pjlink.mute is False, 'Audio should be on'
573 assert mock_UpdateIcons.emit.called is True, 'Update icons should have been called'
543574
544 def test_projector_process_clss_one(self):575 def test_projector_process_clss_one(self):
545 """576 """
546 Test class 1 sent from projector577 Test class 1 sent from projector
547 """578 """
548 # GIVEN: Test object579 # GIVEN: Test object
549 pjlink = pjlink_test580 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
550581
551 # WHEN: Process class response582 # WHEN: Process class response
552 pjlink.process_clss('1')583 pjlink.process_clss('1')
553584
554 # THEN: Projector class should be set to 1585 # THEN: Projector class should be set to 1
555 self.assertEqual(pjlink.pjlink_class, '1',586 assert pjlink.pjlink_class == '1', 'Projector should have set class=1'
556 'Projector should have set class=1')
557587
558 def test_projector_process_clss_two(self):588 def test_projector_process_clss_two(self):
559 """589 """
560 Test class 2 sent from projector590 Test class 2 sent from projector
561 """591 """
562 # GIVEN: Test object592 # GIVEN: Test object
563 pjlink = pjlink_test593 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
564594
565 # WHEN: Process class response595 # WHEN: Process class response
566 pjlink.process_clss('2')596 pjlink.process_clss('2')
567597
568 # THEN: Projector class should be set to 1598 # THEN: Projector class should be set to 1
569 self.assertEqual(pjlink.pjlink_class, '2',599 assert pjlink.pjlink_class == '2', 'Projector should have set class=2'
570 'Projector should have set class=2')600
571601 def test_projector_process_clss_invalid_nan(self):
572 @patch.object(openlp.core.projectors.pjlink, 'log')602 """
573 def test_projector_process_clss_invalid_nan(self, mock_log):603 Test CLSS reply has no class number
574 """604 """
575 Test CLSS reply has no class number605 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
576 """606 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
577 # GIVEN: Test object607 call('(111.111.111.111) Setting pjlink_class for this projector to "1"')]
578 pjlink = pjlink_test608 log_error_calls = [call('(111.111.111.111) NAN CLSS version reply "Z" - defaulting to class "1"')]
579609
580 # WHEN: Process invalid reply610 # GIVEN: Test object
581 pjlink.process_clss('Z')611 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
582 log_text = '(127.0.0.1) NAN CLSS version reply "Z" - defaulting to class "1"'612 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
583613
584 # THEN: Projector class should be set with default value614 # WHEN: Process invalid reply
585 self.assertEqual(pjlink.pjlink_class, '1',615 pjlink.process_clss('Z')
586 'Non-standard class reply should have set class=1')616
587 mock_log.error.assert_called_once_with(log_text)617 # THEN: Projector class should be set with default value
588618 assert pjlink.pjlink_class == '1', 'Invalid NaN class reply should have set class=1'
589 @patch.object(openlp.core.projectors.pjlink, 'log')619 mock_log.error.assert_has_calls(log_error_calls)
590 def test_projector_process_clss_invalid_no_version(self, mock_log):620 mock_log.debug.assert_has_calls(log_debug_calls)
591 """621
592 Test CLSS reply has no class number622 def test_projector_process_clss_invalid_no_version(self):
593 """623 """
594 # GIVEN: Test object624 Test CLSS reply has no class number
595 pjlink = pjlink_test625 """
596626 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
597 # WHEN: Process invalid reply627 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED])),
598 pjlink.process_clss('Invalid')628 call('(111.111.111.111) Setting pjlink_class for this projector to "1"')]
599 log_text = '(127.0.0.1) No numbers found in class version reply "Invalid" - defaulting to class "1"'629 log_error_calls = [call('(111.111.111.111) No numbers found in class version reply "Invalid" '
600630 '- defaulting to class "1"')]
601 # THEN: Projector class should be set with default value631
602 self.assertEqual(pjlink.pjlink_class, '1',632 # GIVEN: Test object
603 'Non-standard class reply should have set class=1')633 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
604 mock_log.error.assert_called_once_with(log_text)634 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
635
636 # WHEN: Process invalid reply
637 pjlink.process_clss('Invalid')
638
639 # THEN: Projector class should be set with default value
640 assert pjlink.pjlink_class == '1', 'Invalid class reply should have set class=1'
641 mock_log.error.assert_has_calls(log_error_calls)
642 mock_log.debug.assert_has_calls(log_debug_calls)
605643
606 def test_projector_process_erst_all_ok(self):644 def test_projector_process_erst_all_ok(self):
607 """645 """
608 Test test_projector_process_erst_all_ok646 Test to verify pjlink.projector_errors is set to None when no errors
609 """647 """
648 chk_data = '0' * PJLINK_ERST_DATA['DATA_LENGTH']
649
610 # GIVEN: Test object650 # GIVEN: Test object
611 pjlink = pjlink_test651 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
612 chk_test = PJLINK_ERST_STATUS['OK']
613 chk_param = chk_test * len(PJLINK_ERST_POSITIONS)
614652
615 # WHEN: process_erst with no errors653 # WHEN: process_erst with no errors
616 pjlink.process_erst(chk_param)654 pjlink.process_erst(chk_data)
617655
618 # THEN: PJLink instance errors should be None656 # THEN: PJLink instance errors should be None
619 self.assertIsNone(pjlink.projector_errors, 'projector_errors should have been set to None')657 assert pjlink.projector_errors is None, 'projector_errors should have been set to None'
620658
621 @patch.object(openlp.core.projectors.pjlink, 'log')659 def test_projector_process_erst_data_invalid_length(self):
622 def test_projector_process_erst_data_invalid_length(self, mock_log):
623 """660 """
624 Test test_projector_process_erst_data_invalid_length661 Test test_projector_process_erst_data_invalid_length
625 """662 """
663 chk_data = '0' * (PJLINK_ERST_DATA['DATA_LENGTH'] + 1)
664 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
665 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED]))]
666 log_warn_calls = [call('111.111.111.111) Invalid error status response "0000000": '
667 'length != {chk}'.format(chk=PJLINK_ERST_DATA['DATA_LENGTH']))]
668
626 # GIVEN: Test object669 # GIVEN: Test object
627 pjlink = pjlink_test670 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
628 pjlink.projector_errors = None671 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
629 log_text = '127.0.0.1) Invalid error status response "11111111": length != 6'672 pjlink.projector_errors = None
630673
631 # WHEN: process_erst called with invalid data (too many values674 # WHEN: process_erst called with invalid data (too many values
632 pjlink.process_erst('11111111')675 pjlink.process_erst(chk_data)
633676
634 # THEN: pjlink.projector_errors should be empty and warning logged677 # THEN: pjlink.projector_errors should be empty and warning logged
635 self.assertIsNone(pjlink.projector_errors, 'There should be no errors')678 assert pjlink.projector_errors is None, 'There should be no errors'
636 self.assertTrue(mock_log.warning.called, 'Warning should have been logged')679 mock_log.debug.assert_has_calls(log_debug_calls)
637 mock_log.warning.assert_called_once_with(log_text)680 mock_log.warning.assert_has_calls(log_warn_calls)
638681
639 @patch.object(openlp.core.projectors.pjlink, 'log')682 def test_projector_process_erst_data_invalid_nan(self):
640 def test_projector_process_erst_data_invalid_nan(self, mock_log):
641 """683 """
642 Test test_projector_process_erst_data_invalid_nan684 Test test_projector_process_erst_data_invalid_nan
643 """685 """
686 chk_data = 'Z' + ('0' * (PJLINK_ERST_DATA['DATA_LENGTH'] - 1))
687 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is '
688 '{state}'.format(state=STATUS_CODE[S_NOT_CONNECTED]))]
689 log_warn_calls = [call('(111.111.111.111) Invalid error status response "Z00000"')]
690
644 # GIVEN: Test object691 # GIVEN: Test object
645 pjlink = pjlink_test692 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
646 pjlink.projector_errors = None693 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
647 log_text = '(127.0.0.1) Invalid error status response "1111Z1"'694 pjlink.projector_errors = None
648695
649 # WHEN: process_erst called with invalid data (too many values696 # WHEN: process_erst called with invalid data (too many values
650 pjlink.process_erst('1111Z1')697 pjlink.process_erst(chk_data)
651698
652 # THEN: pjlink.projector_errors should be empty and warning logged699 # THEN: pjlink.projector_errors should be empty and warning logged
653 self.assertIsNone(pjlink.projector_errors, 'There should be no errors')700 assert pjlink.projector_errors is None, 'There should be no errors'
654 self.assertTrue(mock_log.warning.called, 'Warning should have been logged')701 mock_log.debug.assert_has_calls(log_debug_calls)
655 mock_log.warning.assert_called_once_with(log_text)702 mock_log.warning.assert_has_calls(log_warn_calls)
656703
657 def test_projector_process_erst_all_warn(self):704 def test_projector_process_erst_all_warn(self):
658 """705 """
659 Test test_projector_process_erst_all_warn706 Test test_projector_process_erst_all_warn
660 """707 """
708 chk_data = '{fan}{lamp}{temp}{cover}{filt}{other}'.format(fan=PJLINK_ERST_STATUS[E_WARN],
709 lamp=PJLINK_ERST_STATUS[E_WARN],
710 temp=PJLINK_ERST_STATUS[E_WARN],
711 cover=PJLINK_ERST_STATUS[E_WARN],
712 filt=PJLINK_ERST_STATUS[E_WARN],
713 other=PJLINK_ERST_STATUS[E_WARN])
714 chk_test = {'Fan': E_WARN,
715 'Lamp': E_WARN,
716 'Temperature': E_WARN,
717 'Cover': E_WARN,
718 'Filter': E_WARN,
719 'Other': E_WARN}
720
661 # GIVEN: Test object721 # GIVEN: Test object
662 pjlink = pjlink_test722 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
663 chk_test = PJLINK_ERST_STATUS[E_WARN]723 pjlink.projector_errors = None
664 chk_string = ERROR_STRING[E_WARN]
665 chk_param = chk_test * len(PJLINK_ERST_POSITIONS)
666724
667 # WHEN: process_erst with status set to WARN725 # WHEN: process_erst with status set to WARN
668 pjlink.process_erst(chk_param)726 pjlink.process_erst(chk_data)
669727
670 # THEN: PJLink instance errors should match chk_value728 # THEN: PJLink instance errors should match chk_value
671 for chk in pjlink.projector_errors:729 assert pjlink.projector_errors == chk_test, 'Projector errors should be all E_WARN'
672 self.assertEqual(pjlink.projector_errors[chk], chk_string,
673 'projector_errors["{chk}"] should have been set to "{err}"'.format(chk=chk,
674 err=chk_string))
675730
676 def test_projector_process_erst_all_error(self):731 def test_projector_process_erst_all_error(self):
677 """732 """
678 Test test_projector_process_erst_all_error733 Test test_projector_process_erst_all_error
679 """734 """
735 chk_data = '{fan}{lamp}{temp}{cover}{filt}{other}'.format(fan=PJLINK_ERST_STATUS[E_ERROR],
736 lamp=PJLINK_ERST_STATUS[E_ERROR],
737 temp=PJLINK_ERST_STATUS[E_ERROR],
738 cover=PJLINK_ERST_STATUS[E_ERROR],
739 filt=PJLINK_ERST_STATUS[E_ERROR],
740 other=PJLINK_ERST_STATUS[E_ERROR])
741 chk_test = {'Fan': E_ERROR,
742 'Lamp': E_ERROR,
743 'Temperature': E_ERROR,
744 'Cover': E_ERROR,
745 'Filter': E_ERROR,
746 'Other': E_ERROR}
747
680 # GIVEN: Test object748 # GIVEN: Test object
681 pjlink = pjlink_test749 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
682 chk_test = PJLINK_ERST_STATUS[E_ERROR]750 pjlink.projector_errors = None
683 chk_string = ERROR_STRING[E_ERROR]
684 chk_param = chk_test * len(PJLINK_ERST_POSITIONS)
685751
686 # WHEN: process_erst with status set to WARN752 # WHEN: process_erst with status set to WARN
687 pjlink.process_erst(chk_param)753 pjlink.process_erst(chk_data)
688754
689 # THEN: PJLink instance errors should match chk_value755 # THEN: PJLink instance errors should match chk_value
690 for chk in pjlink.projector_errors:756 assert pjlink.projector_errors == chk_test, 'Projector errors should be all E_ERROR'
691 self.assertEqual(pjlink.projector_errors[chk], chk_string,
692 'projector_errors["{chk}"] should have been set to "{err}"'.format(chk=chk,
693 err=chk_string))
694757
695 def test_projector_process_erst_warn_cover_only(self):758 def test_projector_process_erst_warn_cover_only(self):
696 """759 """
697 Test test_projector_process_erst_warn_cover_only760 Test test_projector_process_erst_warn_cover_only
698 """761 """
762 chk_data = '{fan}{lamp}{temp}{cover}{filt}{other}'.format(fan=PJLINK_ERST_STATUS[S_OK],
763 lamp=PJLINK_ERST_STATUS[S_OK],
764 temp=PJLINK_ERST_STATUS[S_OK],
765 cover=PJLINK_ERST_STATUS[E_WARN],
766 filt=PJLINK_ERST_STATUS[S_OK],
767 other=PJLINK_ERST_STATUS[S_OK])
768 chk_test = {'Cover': E_WARN}
769
699 # GIVEN: Test object770 # GIVEN: Test object
700 pjlink = pjlink_test771 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
701 chk_test = PJLINK_ERST_STATUS[E_WARN]772 pjlink.projector_errors = None
702 chk_string = ERROR_STRING[E_WARN]773
703 pos = PJLINK_ERST_DATA['COVER']774 # WHEN: process_erst with status set to WARN
704 build_chk = []775 pjlink.process_erst(chk_data)
705 for check in range(0, len(PJLINK_ERST_POSITIONS)):776
706 if check == pos:777 # THEN: PJLink instance errors should match only cover warning
707 build_chk.append(chk_test)778 assert 1 == len(pjlink.projector_errors), 'There should only be 1 error listed in projector_errors'
708 else:779 assert 'Cover' in pjlink.projector_errors, '"Cover" should be the only error listed'
709 build_chk.append(PJLINK_ERST_STATUS['OK'])780 assert pjlink.projector_errors['Cover'] == E_WARN, '"Cover" should have E_WARN listed as error'
710 chk_param = ''.join(build_chk)781 assert chk_test == pjlink.projector_errors, 'projector_errors should match test errors'
711782
712 # WHEN: process_erst with cover only set to WARN and all others set to OK783 def test_projector_process_inpt_valid(self):
713 pjlink.process_erst(chk_param)
714
715 # THEN: Only COVER should have an error
716 self.assertEqual(len(pjlink.projector_errors), 1, 'projector_errors should only have 1 error')
717 self.assertTrue(('Cover' in pjlink.projector_errors), 'projector_errors should have an error for "Cover"')
718 self.assertEqual(pjlink.projector_errors['Cover'],
719 chk_string,
720 'projector_errors["Cover"] should have error "{err}"'.format(err=chk_string))
721
722 def test_projector_process_inpt(self):
723 """784 """
724 Test input source status shows current input785 Test input source status shows current input
725 """786 """
787 log_debug_calls = [call('(111.111.111.111) reset_information() connect status is S_NOT_CONNECTED')]
788 chk_source_available = ['11', '12', '21', '22', '31', '32']
789
726 # GIVEN: Test object790 # GIVEN: Test object
727 pjlink = pjlink_test791 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
728 pjlink.source = '0'792 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
729793 pjlink.source_available = chk_source_available
730 # WHEN: Called with input source794 pjlink.source = '11'
731 pjlink.process_inpt('1')795
732796 # WHEN: Called with input source
733 # THEN: Input selected should reflect current input797 pjlink.process_inpt('21')
734 self.assertEqual(pjlink.source, '1', 'Input source should be set to "1"')798
735799 # THEN: Input selected should reflect current input
736 @patch.object(pjlink_test, 'projectorUpdateIcons')800 assert pjlink.source == '21', 'Input source should be set to "21"'
737 @patch.object(openlp.core.projectors.pjlink, 'log')801 mock_log.debug.assert_has_calls(log_debug_calls)
738 def test_projector_process_inst(self, mock_log, mock_UpdateIcons):802
803 def test_projector_process_input_not_in_list(self):
804 """
805 Test setting input outside of available inputs
806
807 TODO: Future test
808 """
809 pass
810
811 def test_projector_process_input_not_in_default(self):
812 """
813 Test setting input with no sources available
814 TODO: Future test
815 """
816 pass
817
818 def test_projector_process_input_invalid(self):
819 """
820 Test setting input with an invalid value
821
822 TODO: Future test
823 """
824
825 def test_projector_process_inst_class_1(self):
739 """826 """
740 Test saving video source available information827 Test saving video source available information
741 """828 """
829 log_debug_calls = [call('(111.111.111.111) Setting projector sources_available to '
830 '"[\'11\', \'12\', \'21\', \'22\', \'31\', \'32\']"')]
831 chk_data = '21 12 11 22 32 31' # Although they should already be sorted, use unsorted to verify method
832 chk_test = ['11', '12', '21', '22', '31', '32']
833
742 # GIVEN: Test object834 # GIVEN: Test object
743 pjlink = pjlink_test835 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
744 pjlink.source_available = []836 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
745 test_data = '21 10 30 31 11 20'837 pjlink.source_available = []
746 test_saved = ["10", "11", "20", "21", "30", "31"]838
747 log_data = "(127.0.0.1) Setting projector sources_available to " \839 # WHEN: process_inst called with test data
748 "\"['10', '11', '20', '21', '30', '31']\""840 pjlink.process_inst(data=chk_data)
749 mock_UpdateIcons.reset_mock()841
750 mock_log.reset_mock()842 # THEN: Data should have been sorted and saved properly
751843 assert pjlink.source_available == chk_test, "Sources should have been sorted and saved"
752 # WHEN: process_inst called with test data844 mock_log.debug.assert_has_calls(log_debug_calls)
753 pjlink.process_inst(data=test_data)845
754846 def test_projector_process_lamp_invalid(self):
755 # THEN: Data should have been sorted and saved properly
756 self.assertEqual(pjlink.source_available, test_saved, "Sources should have been sorted and saved")
757 mock_log.debug.assert_called_once_with(log_data)
758 self.assertTrue(mock_UpdateIcons.emit.called, 'Update Icons should have been called')
759
760 @patch.object(openlp.core.projectors.pjlink, 'log')
761 def test_projector_process_lamp_invalid(self, mock_log):
762 """847 """
763 Test status multiple lamp on/off and hours848 Test status multiple lamp on/off and hours
764 """849 """
850 log_data = [call('(111.111.111.111) process_lamp(): Invalid data "11111 1 22222 0 333A3 1"')]
851
765 # GIVEN: Test object852 # GIVEN: Test object
766 pjlink = pjlink_test853 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
767 pjlink.lamp = [{'Hours': 00000, 'On': True},854 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
768 {'Hours': 11111, 'On': False}]855 pjlink.lamp = [{'Hours': 00000, 'On': True},
769 log_data = '(127.0.0.1) process_lamp(): Invalid data "11111 1 22222 0 333A3 1"'856 {'Hours': 11111, 'On': False}]
770857
771 # WHEN: Call process_command with invalid lamp data858 # WHEN: Call process_command with invalid lamp data
772 pjlink.process_lamp('11111 1 22222 0 333A3 1')859 pjlink.process_lamp('11111 1 22222 0 333A3 1')
773860
774 # THEN: lamps should not have changed861 # THEN: lamps should not have changed
775 self.assertEqual(len(pjlink.lamp), 2,862 assert 2 == len(pjlink.lamp), 'Projector should have kept 2 lamps specified'
776 'Projector should have kept 2 lamps specified')863 assert pjlink.lamp[0]['On'] is True, 'Lamp 1 power status should have stayed TRUE'
777 self.assertEqual(pjlink.lamp[0]['On'], True,864 assert 00000 == pjlink.lamp[0]['Hours'], 'Lamp 1 hours should have been left at 00000'
778 'Lamp 1 power status should have been set to TRUE')865 assert pjlink.lamp[1]['On'] is False, 'Lamp 2 power status should have stayed FALSE'
779 self.assertEqual(pjlink.lamp[0]['Hours'], 00000,866 assert 11111 == pjlink.lamp[1]['Hours'], 'Lamp 2 hours should have been left at 11111'
780 'Lamp 1 hours should have been left at 00000')867 mock_log.warning.assert_has_calls(log_data)
781 self.assertEqual(pjlink.lamp[1]['On'], False,
782 'Lamp 2 power status should have been set to FALSE')
783 self.assertEqual(pjlink.lamp[1]['Hours'], 11111,
784 'Lamp 2 hours should have been left at 11111')
785 mock_log.warning.assert_called_once_with(log_data)
786868
787 def test_projector_process_lamp_multiple(self):869 def test_projector_process_lamp_multiple(self):
788 """870 """
789 Test status multiple lamp on/off and hours871 Test status multiple lamp on/off and hours
790 """872 """
791 # GIVEN: Test object873 # GIVEN: Test object
792 pjlink = pjlink_test874 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
793 pjlink.lamps = []875 pjlink.lamp = []
794876
795 # WHEN: Call process_command with lamp data877 # WHEN: Call process_command with invalid lamp data
796 pjlink.process_lamp('11111 1 22222 0 33333 1')878 pjlink.process_lamp('11111 1 22222 0 33333 1')
797879
798 # THEN: Lamp should have been set with proper lamp status880 # THEN: Lamp should have been set with proper lamp status
799 self.assertEqual(len(pjlink.lamp), 3,881 assert 3 == len(pjlink.lamp), 'Projector should have 3 lamps specified'
800 'Projector should have 3 lamps specified')882 assert pjlink.lamp[0]['On'] is True, 'Lamp 1 power status should have been set to TRUE'
801 self.assertEqual(pjlink.lamp[0]['On'], True,883 assert 11111 == pjlink.lamp[0]['Hours'], 'Lamp 1 hours should have been set to 11111'
802 'Lamp 1 power status should have been set to TRUE')884 assert pjlink.lamp[1]['On'] is False, 'Lamp 2 power status should have been set to FALSE'
803 self.assertEqual(pjlink.lamp[0]['Hours'], 11111,885 assert 22222 == pjlink.lamp[1]['Hours'], 'Lamp 2 hours should have been set to 22222'
804 'Lamp 1 hours should have been set to 11111')886 assert pjlink.lamp[2]['On'] is True, 'Lamp 3 power status should have been set to TRUE'
805 self.assertEqual(pjlink.lamp[1]['On'], False,887 assert 33333 == pjlink.lamp[2]['Hours'], 'Lamp 3 hours should have been set to 33333'
806 'Lamp 2 power status should have been set to FALSE')
807 self.assertEqual(pjlink.lamp[1]['Hours'], 22222,
808 'Lamp 2 hours should have been set to 22222')
809 self.assertEqual(pjlink.lamp[2]['On'], True,
810 'Lamp 3 power status should have been set to TRUE')
811 self.assertEqual(pjlink.lamp[2]['Hours'], 33333,
812 'Lamp 3 hours should have been set to 33333')
813888
814 def test_projector_process_lamp_single(self):889 def test_projector_process_lamp_single(self):
815 """890 """
816 Test status lamp on/off and hours891 Test status lamp on/off and hours
817 """892 """
893
818 # GIVEN: Test object894 # GIVEN: Test object
819 pjlink = pjlink_test895 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
820 pjlink.lamps = []896 pjlink.lamp = []
821897
822 # WHEN: Call process_command with lamp data898 # WHEN: Call process_command with invalid lamp data
823 pjlink.process_lamp('22222 1')899 pjlink.process_lamp('22222 1')
824900
825 # THEN: Lamp should have been set with status=ON and hours=22222901 # THEN: Lamp should have been set with status=ON and hours=22222
826 self.assertEqual(pjlink.lamp[0]['On'], True,902 assert 1 == len(pjlink.lamp), 'Projector should have only 1 lamp'
827 'Lamp power status should have been set to TRUE')903 assert pjlink.lamp[0]['On'] is True, 'Lamp power status should have been set to TRUE'
828 self.assertEqual(pjlink.lamp[0]['Hours'], 22222,904 assert 22222 == pjlink.lamp[0]['Hours'], 'Lamp hours should have been set to 22222'
829 'Lamp hours should have been set to 22222')
830905
831 @patch.object(openlp.core.projectors.pjlink, 'log')906 def test_projector_process_name(self):
832 def test_projector_process_name(self, mock_log):
833 """907 """
834 Test saving NAME data from projector908 Test saving NAME data from projector
835 """909 """
836 # GIVEN: Test data910 chk_data = "Some Name the End-User Set IN Projector"
837 pjlink = pjlink_test911 log_debug_calls = [call('(111.111.111.111) Setting projector PJLink name to '
838 test_data = "Some Name the End-User Set IN Projector"912 '"Some Name the End-User Set IN Projector"')]
839 test_log = '(127.0.0.1) Setting projector PJLink name to "Some Name the End-User Set IN Projector"'913
840 mock_log.reset_mock()914 # GIVEN: Test object
841915 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
842 # WHEN: process_name called with test data916 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
843 pjlink.process_name(data=test_data)917
844918 # WHEN: process_name called with test data
845 # THEN: name should be set and logged919 pjlink.process_name(data=chk_data)
846 self.assertEqual(pjlink.pjlink_name, test_data, 'Name test data should have been saved')920
847 mock_log.debug.assert_called_once_with(test_log)921 # THEN: name should be set and logged
848922 assert pjlink.pjlink_name == chk_data, 'Name test data should have been saved'
849 @patch.object(pjlink_test, 'projectorUpdateIcons')923 mock_log.debug.assert_has_calls(log_debug_calls)
850 @patch.object(pjlink_test, 'send_command')924
851 @patch.object(pjlink_test, 'change_status')925 def test_projector_process_powr_on(self):
852 def test_projector_process_powr_on(self,
853 mock_change_status,
854 mock_send_command,
855 mock_UpdateIcons):
856 """926 """
857 Test status power to ON927 Test status power to ON
858 """928 """
859 # GIVEN: Test object and preset929 # GIVEN: Test object
860 pjlink = pjlink_test930 with patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
861 pjlink.power = S_STANDBY931 patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
862 test_data = PJLINK_POWR_STATUS[S_ON]932 patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
863933
864 # WHEN: Call process_command with turn power on command934 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
865 pjlink.process_command(cmd='POWR', data=test_data)935 pjlink.power = S_STANDBY
866936
867 # THEN: Power should be set to ON937 # WHEN: process_name called with test data
868 self.assertEqual(pjlink.power, S_ON, 'Power should have been set to ON')938 pjlink.process_powr(data=PJLINK_POWR_STATUS[S_ON])
869 mock_send_command.assert_called_once_with('INST')939
870 mock_change_status.assert_called_once_with(PJLINK_POWR_STATUS[test_data])940 # THEN: Power should be set to ON
871 self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')941 assert pjlink.power == S_ON, 'Power should have been set to ON'
872942 assert mock_UpdateIcons.emit.called is True, 'projectorUpdateIcons should have been called'
873 @patch.object(pjlink_test, 'projectorUpdateIcons')943 mock_send_command.assert_called_once_with('INST')
874 @patch.object(pjlink_test, 'send_command')944 mock_change_status.assert_called_once_with(S_ON)
875 @patch.object(pjlink_test, 'change_status')945
876 def test_projector_process_powr_invalid(self,946 def test_projector_process_powr_invalid(self):
877 mock_change_status,
878 mock_send_command,
879 mock_UpdateIcons):
880 """947 """
881 Test process_powr invalid call948 Test process_powr invalid call
882 """949 """
883 # GIVEN: Test object and preset950 log_warn_calls = [call('(111.111.111.111) Unknown power response: "99"')]
884 pjlink = pjlink_test951
885 pjlink.power = S_STANDBY952 # GIVEN: Test object
886 test_data = '99'953 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
887954 patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
888 # WHEN: Call process_command with turn power on command955 patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
889 pjlink.process_command(cmd='POWR', data=test_data)956 patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
890957
891 # THEN: Power should be set to ON958 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
892 self.assertEqual(pjlink.power, S_STANDBY, 'Power should not have changed')959 pjlink.power = S_STANDBY
893 self.assertFalse(mock_change_status.called, 'Change status should not have been called')960
894 self.assertFalse(mock_send_command.called, 'send_command("INST") should not have been called')961 # WHEN: process_name called with test data
895 self.assertFalse(mock_UpdateIcons.emit.called, 'projectorUpdateIcons should not have been called')962 pjlink.process_powr(data='99')
896963
897 @patch.object(pjlink_test, 'projectorUpdateIcons')964 # THEN: Power should be set to ON
898 @patch.object(pjlink_test, 'send_command')965 assert pjlink.power == S_STANDBY, 'Power should not have changed'
899 @patch.object(pjlink_test, 'change_status')966 assert mock_UpdateIcons.emit.called is False, 'projectorUpdateIcons() should not have been called'
900 def test_projector_process_powr_off(self,967 mock_change_status.called is False, 'change_status() should not have been called'
901 mock_change_status,968 mock_send_command.called is False, 'send_command() should not have been called'
902 mock_send_command,969 mock_log.warning.assert_has_calls(log_warn_calls)
903 mock_UpdateIcons):970
971 def test_projector_process_powr_off(self):
904 """972 """
905 Test status power to STANDBY973 Test status power to STANDBY
906 """974 """
907 # GIVEN: Test object and preset975 # GIVEN: Test object
908 pjlink = pjlink_test976 with patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
909 pjlink.power = S_ON977 patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
910 test_data = PJLINK_POWR_STATUS[S_STANDBY]978 patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorUpdateIcons') as mock_UpdateIcons:
911979
912 # WHEN: Call process_command with turn power on command980 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
913 pjlink.process_command(cmd='POWR', data=test_data)981 pjlink.power = S_ON
914982
915 # THEN: Power should be set to STANDBY983 # WHEN: process_name called with test data
916 self.assertEqual(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')984 pjlink.process_powr(data=PJLINK_POWR_STATUS[S_STANDBY])
917 self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')985
918 mock_change_status.assert_called_once_with(PJLINK_POWR_STATUS[test_data])986 # THEN: Power should be set to ON
919 self.assertFalse(mock_send_command.called, "send_command['INST'] should not have been called")987 assert pjlink.power == S_STANDBY, 'Power should have changed to S_STANDBY'
988 assert mock_UpdateIcons.emit.called is True, 'projectorUpdateIcons should have been called'
989 mock_change_status.called is True, 'change_status should have been called'
990 mock_send_command.called is False, 'send_command should not have been called'
920991
921 def test_projector_process_rfil_save(self):992 def test_projector_process_rfil_save(self):
922 """993 """
923 Test saving filter type994 Test saving filter type
924 """995 """
996 filter_model = 'Filter Type Test'
997
925 # GIVEN: Test object998 # GIVEN: Test object
926 pjlink = pjlink_test999 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
927 pjlink.model_filter = None1000 pjlink.model_filter = None
928 filter_model = 'Filter Type Test'
9291001
930 # WHEN: Filter model is received1002 # WHEN: Filter model is received
931 pjlink.process_rfil(data=filter_model)1003 pjlink.process_rfil(data=filter_model)
9321004
933 # THEN: Filter model number should be saved1005 # THEN: Filter model number should be saved
934 self.assertEqual(pjlink.model_filter, filter_model, 'Filter type should have been saved')1006 assert pjlink.model_filter == filter_model, 'Filter type should have been saved'
9351007
936 def test_projector_process_rfil_nosave(self):1008 def test_projector_process_rfil_nosave(self):
937 """1009 """
938 Test saving filter type previously saved1010 Test saving filter type previously saved
939 """1011 """
1012 filter_model = 'Filter Type Test'
1013 log_warn_calls = [call('(111.111.111.111) Filter model already set'),
1014 call('(111.111.111.111) Saved model: "Old filter type"'),
1015 call('(111.111.111.111) New model: "Filter Type Test"')]
1016
940 # GIVEN: Test object1017 # GIVEN: Test object
941 pjlink = pjlink_test1018 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
942 pjlink.model_filter = 'Old filter type'1019
943 filter_model = 'Filter Type Test'1020 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
9441021 pjlink.model_filter = 'Old filter type'
945 # WHEN: Filter model is received1022
946 pjlink.process_rfil(data=filter_model)1023 # WHEN: Filter model is received
9471024 pjlink.process_rfil(data=filter_model)
948 # THEN: Filter model number should be saved1025
949 self.assertNotEquals(pjlink.model_filter, filter_model, 'Filter type should NOT have been saved')1026 # THEN: Filter model number should be saved
1027 assert pjlink.model_filter != filter_model, 'Filter type should NOT have been saved'
1028 mock_log.warning.assert_has_calls(log_warn_calls)
9501029
951 def test_projector_process_rlmp_save(self):1030 def test_projector_process_rlmp_save(self):
952 """1031 """
953 Test saving lamp type1032 Test saving lamp type
954 """1033 """
955 # GIVEN: Test object1034 # GIVEN: Test object
956 pjlink = pjlink_test1035 # GIVEN: Test object
1036 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
957 pjlink.model_lamp = None1037 pjlink.model_lamp = None
958 lamp_model = 'Lamp Type Test'1038 lamp_model = 'Lamp Type Test'
9591039
@@ -961,159 +1041,179 @@
961 pjlink.process_rlmp(data=lamp_model)1041 pjlink.process_rlmp(data=lamp_model)
9621042
963 # THEN: Filter model number should be saved1043 # THEN: Filter model number should be saved
964 self.assertEqual(pjlink.model_lamp, lamp_model, 'Lamp type should have been saved')1044 assert pjlink.model_lamp == lamp_model, 'Lamp type should have been saved'
9651045
966 def test_projector_process_rlmp_nosave(self):1046 def test_projector_process_rlmp_nosave(self):
967 """1047 """
968 Test saving lamp type previously saved1048 Test saving lamp type previously saved
969 """1049 """
1050 lamp_model = 'Lamp Type Test'
1051 log_warn_calls = [call('(111.111.111.111) Lamp model already set'),
1052 call('(111.111.111.111) Saved lamp: "Old lamp type"'),
1053 call('(111.111.111.111) New lamp: "Lamp Type Test"')]
1054
970 # GIVEN: Test object1055 # GIVEN: Test object
971 pjlink = pjlink_test1056 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
972 pjlink.model_lamp = 'Old lamp type'1057
973 lamp_model = 'Filter Type Test'1058 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
9741059 pjlink.model_lamp = 'Old lamp type'
975 # WHEN: Filter model is received1060
976 pjlink.process_rlmp(data=lamp_model)1061 # WHEN: Filter model is received
9771062 pjlink.process_rlmp(data=lamp_model)
978 # THEN: Filter model number should be saved1063
979 self.assertNotEquals(pjlink.model_lamp, lamp_model, 'Lamp type should NOT have been saved')1064 # THEN: Filter model number should be saved
1065 assert pjlink.model_lamp != lamp_model, 'Lamp type should NOT have been saved'
1066 mock_log.warning.assert_has_calls(log_warn_calls)
9801067
981 def test_projector_process_snum_set(self):1068 def test_projector_process_snum_set(self):
982 """1069 """
983 Test saving serial number from projector1070 Test saving serial number from projector
984 """1071 """
1072 log_debug_calls = [call('(111.111.111.111) Setting projector serial number to "Test Serial Number"')]
1073 test_number = 'Test Serial Number'
1074
985 # GIVEN: Test object1075 # GIVEN: Test object
986 pjlink = pjlink_test1076 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
987 pjlink.serial_no = None1077
988 test_number = 'Test Serial Number'1078 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
9891079 pjlink.serial_no = None
990 # WHEN: No serial number is set and we receive serial number command1080
991 pjlink.process_snum(data=test_number)1081 # WHEN: No serial number is set and we receive serial number command
9921082 pjlink.process_snum(data=test_number)
993 # THEN: Serial number should be set1083
994 self.assertEqual(pjlink.serial_no, test_number,1084 # THEN: Serial number should be set
995 'Projector serial number should have been set')1085 assert pjlink.serial_no == test_number, 'Projector serial number should have been set'
1086 mock_log.debug.assert_has_calls(log_debug_calls)
9961087
997 def test_projector_process_snum_different(self):1088 def test_projector_process_snum_different(self):
998 """1089 """
999 Test projector serial number different than saved serial number1090 Test projector serial number different than saved serial number
1000 """1091 """
1001 # GIVEN: Test object1092 log_warn_calls = [call('(111.111.111.111) Projector serial number does not match saved serial number'),
1002 pjlink = pjlink_test1093 call('(111.111.111.111) Saved: "Previous serial number"'),
1003 pjlink.serial_no = 'Previous serial number'1094 call('(111.111.111.111) Received: "Test Serial Number"'),
1095 call('(111.111.111.111) NOT saving serial number')]
1004 test_number = 'Test Serial Number'1096 test_number = 'Test Serial Number'
10051097
1006 # WHEN: No serial number is set and we receive serial number command1098 # GIVEN: Test object
1007 pjlink.process_snum(data=test_number)1099 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
10081100 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1009 # THEN: Serial number should be set1101 pjlink.serial_no = 'Previous serial number'
1010 self.assertNotEquals(pjlink.serial_no, test_number,1102
1011 'Projector serial number should NOT have been set')1103 # WHEN: No serial number is set and we receive serial number command
10121104 pjlink.process_snum(data=test_number)
1013 @patch.object(openlp.core.projectors.pjlink, 'log')1105
1014 def test_projector_process_sver(self, mock_log):1106 # THEN: Serial number should be set
1107 assert pjlink.serial_no != test_number, 'Projector serial number should NOT have been set'
1108 mock_log.warning.assert_has_calls(log_warn_calls)
1109
1110 def test_projector_process_sver(self):
1015 """1111 """
1016 Test invalid software version information - too long1112 Test invalid software version information - too long
1017 """1113 """
1018 # GIVEN: Test object
1019 pjlink = pjlink_test
1020 pjlink.sw_version = None
1021 pjlink.sw_version_received = None
1022 test_data = 'Test 1 Subtest 1'1114 test_data = 'Test 1 Subtest 1'
1023 test_log = '(127.0.0.1) Setting projector software version to "Test 1 Subtest 1"'1115 log_debug_calls = [call('(111.111.111.111) Setting projector software version to "Test 1 Subtest 1"')]
1024 mock_log.reset_mock()1116
10251117 # GIVEN: Test object
1026 # WHEN: process_sver called with invalid data1118 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
1027 pjlink.process_sver(data=test_data)1119 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
10281120 pjlink.sw_version = None
1029 # THEN: Version information should not change1121 pjlink.sw_version_received = None
1030 self.assertEqual(pjlink.sw_version, test_data, 'Software version should have been updated')1122
1031 self.assertIsNone(pjlink.sw_version_received, 'Received software version should not have changed')1123 # WHEN: process_sver called with invalid data
1032 mock_log.debug.assert_called_once_with(test_log)1124 pjlink.process_sver(data=test_data)
10331125
1034 @patch.object(openlp.core.projectors.pjlink, 'log')1126 # THEN: Version information should not change
1035 def test_projector_process_sver_changed(self, mock_log):1127 assert pjlink.sw_version == test_data, 'Software version should have been updated'
1128 mock_log.debug.assert_has_calls(log_debug_calls)
1129
1130 def test_projector_process_sver_changed(self):
1036 """1131 """
1037 Test invalid software version information - Received different than saved1132 Test invalid software version information - Received different than saved
1038 """1133 """
1039 # GIVEN: Test object1134 test_data_old = 'Test 1 Subtest 1'
1040 pjlink = pjlink_test
1041 test_data_new = 'Test 1 Subtest 2'1135 test_data_new = 'Test 1 Subtest 2'
1042 test_data_old = 'Test 1 Subtest 1'1136 log_warn_calls = [call('(111.111.111.111) Projector software version does not match saved software version'),
1043 pjlink.sw_version = test_data_old1137 call('(111.111.111.111) Saved: "Test 1 Subtest 1"'),
1044 pjlink.sw_version_received = None1138 call('(111.111.111.111) Received: "Test 1 Subtest 2"'),
1045 test_log = '(127.0.0.1) Saving new serial number as sw_version_received'1139 call('(111.111.111.111) Updating software version')]
1046 mock_log.reset_mock()1140
10471141 # GIVEN: Test object
1048 # WHEN: process_sver called with invalid data1142 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
1049 pjlink.process_sver(data=test_data_new)1143 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
10501144 pjlink.sw_version = test_data_old
1051 # THEN: Version information should not change1145
1052 self.assertEqual(pjlink.sw_version, test_data_old, 'Software version should not have been updated')1146 # WHEN: process_sver called with invalid data
1053 self.assertEqual(pjlink.sw_version_received, test_data_new,1147 pjlink.process_sver(data=test_data_new)
1054 'Received software version should have been changed')1148
1055 self.assertEqual(mock_log.warning.call_count, 4, 'log.warn should have been called 4 times')1149 # THEN: Version information should not change
1056 # There was 4 calls, but only the last one is checked with this method1150 assert pjlink.sw_version == test_data_new, 'Software version should have changed'
1057 mock_log.warning.assert_called_with(test_log)1151 mock_log.warning.assert_has_calls(log_warn_calls)
10581152
1059 @patch.object(openlp.core.projectors.pjlink, 'log')1153 def test_projector_process_sver_invalid(self):
1060 def test_projector_process_sver_invalid(self, mock_log):
1061 """1154 """
1062 Test invalid software version information - too long1155 Test invalid software version information - too long
1063 """1156 """
1064 # GIVEN: Test object
1065 pjlink = pjlink_test
1066 pjlink.sw_version = None
1067 pjlink.sw_version_received = None
1068 test_data = 'This is a test software version line that is too long based on PJLink version 2 specs'1157 test_data = 'This is a test software version line that is too long based on PJLink version 2 specs'
1069 test_log = "Invalid software version - too long"1158 log_warn_calls = [call('Invalid software version - too long')]
1070 mock_log.reset_mock()1159
10711160 # GIVEN: Test object
1072 # WHEN: process_sver called with invalid data1161 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
1073 pjlink.process_sver(data=test_data)1162 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
10741163 pjlink.sw_version = None
1075 # THEN: Version information should not change1164
1076 self.assertIsNone(pjlink.sw_version, 'Software version should not have changed')1165 # WHEN: process_sver called with invalid data
1077 self.assertIsNone(pjlink.sw_version_received, 'Received software version should not have changed')1166 pjlink.process_sver(data=test_data)
1078 mock_log.warning.assert_called_once_with(test_log)1167
1168 # THEN: Version information should not change
1169 assert pjlink.sw_version is None, 'Software version should not have changed'
1170 assert pjlink.sw_version_received is None, 'Received software version should not have changed'
1171 mock_log.warning.assert_has_calls(log_warn_calls)
10791172
1080 def test_projector_reset_information(self):1173 def test_projector_reset_information(self):
1081 """1174 """
1082 Test reset_information() resets all information and stops timers1175 Test reset_information() resets all information and stops timers
1083 """1176 """
1084 # GIVEN: Test object and test data1177 log_debug_calls = [call('(111.111.111.111): Calling timer.stop()'),
1085 pjlink = pjlink_test1178 call('(111.111.111.111): Calling socket_timer.stop()')]
1086 pjlink.power = S_ON1179
1087 pjlink.pjlink_name = 'OPENLPTEST'1180 # GIVEN: Test object
1088 pjlink.manufacturer = 'PJLINK'1181 with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log:
1089 pjlink.model = '1'1182 pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
1090 pjlink.shutter = True1183 # timer and socket_timer not available until instantiation, so mock here
1091 pjlink.mute = True1184 with patch.object(pjlink, 'socket_timer') as mock_socket_timer, \
1092 pjlink.lamp = True1185 patch.object(pjlink, 'timer') as mock_timer:
1093 pjlink.fan = True1186
1094 pjlink.source_available = True1187 pjlink.power = S_ON
1095 pjlink.other_info = 'ANOTHER TEST'1188 pjlink.pjlink_name = 'OPENLPTEST'
1096 pjlink.send_queue = True1189 pjlink.manufacturer = 'PJLINK'
1097 pjlink.send_busy = True1190 pjlink.model = '1'
10981191 pjlink.shutter = True
1099 # WHEN: reset_information() is called1192 pjlink.mute = True
1100 with patch.object(pjlink, 'timer') as mock_timer:1193 pjlink.lamp = True
1101 with patch.object(pjlink, 'socket_timer') as mock_socket_timer:1194 pjlink.fan = True
1195 pjlink.source_available = True
1196 pjlink.other_info = 'ANOTHER TEST'
1197 pjlink.send_queue = True
1198 pjlink.send_busy = True
1199
1200 # WHEN: reset_information() is called
1102 pjlink.reset_information()1201 pjlink.reset_information()
11031202
1104 # THEN: All information should be reset and timers stopped1203 # THEN: All information should be reset and timers stopped
1105 self.assertEqual(pjlink.power, S_OFF, 'Projector power should be OFF')1204 assert pjlink.power == S_OFF, 'Projector power should be OFF'
1106 self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None')1205 assert pjlink.pjlink_name is None, 'Projector pjlink_name should be None'
1107 self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None')1206 assert pjlink.manufacturer is None, 'Projector manufacturer should be None'
1108 self.assertIsNone(pjlink.model, 'Projector model should be None')1207 assert pjlink.model is None, 'Projector model should be None'
1109 self.assertIsNone(pjlink.shutter, 'Projector shutter should be None')1208 assert pjlink.shutter is None, 'Projector shutter should be None'
1110 self.assertIsNone(pjlink.mute, 'Projector shuttter should be None')1209 assert pjlink.mute is None, 'Projector shuttter should be None'
1111 self.assertIsNone(pjlink.lamp, 'Projector lamp should be None')1210 assert pjlink.lamp is None, 'Projector lamp should be None'
1112 self.assertIsNone(pjlink.fan, 'Projector fan should be None')1211 assert pjlink.fan is None, 'Projector fan should be None'
1113 self.assertIsNone(pjlink.source_available, 'Projector source_available should be None')1212 assert pjlink.source_available is None, 'Projector source_available should be None'
1114 self.assertIsNone(pjlink.source, 'Projector source should be None')1213 assert pjlink.source is None, 'Projector source should be None'
1115 self.assertIsNone(pjlink.other_info, 'Projector other_info should be None')1214 assert pjlink.other_info is None, 'Projector other_info should be None'
1116 self.assertEqual(pjlink.send_queue, [], 'Projector send_queue should be an empty list')1215 assert pjlink.send_queue == [], 'Projector send_queue should be an empty list'
1117 self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')1216 assert pjlink.send_busy is False, 'Projector send_busy should be False'
1118 self.assertTrue(mock_timer.stop.called, 'Projector timer.stop() should have been called')1217 assert mock_timer.stop.called is True, 'Projector timer.stop() should have been called'
1119 self.assertTrue(mock_socket_timer.stop.called, 'Projector socket_timer.stop() should have been called')1218 assert mock_socket_timer.stop.called is True, 'Projector socket_timer.stop() should have been called'
1219 mock_log.debug.assert_has_calls(log_debug_calls)