mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-29 17:58:47 -04:00
zmcontrol dispatches straight onto the control object with $control->$command(...). A monitor's actions and ui buttons are configured independently of its control protocol, so nothing stops a LightOn action pointing at a protocol with no lightOn, and Perl kills the control server with "Can't locate object method". Swapping a camera for a different make produces exactly that. A monitor whose AMLink camera was replaced by an ONVIF one kept its LightOn and LightOff actions, and ONVIF has neither, so the first alarm after the protocol change would have taken the control server down for that monitor. Check can() before dispatching, log which monitor and command need attention, and answer a caller that asked for a response rather than leaving it hanging. Direct protocol mode gets the same check, as a Fatal, since there the command came from the command line and is a typo worth reporting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UvTCzCbvGt8xKQRNCSA7o8
40 lines
1.9 KiB
Perl
40 lines
1.9 KiB
Perl
use strict;
|
|
use warnings;
|
|
use Test::More tests => 13;
|
|
|
|
# zmcontrol dispatches ui and action commands straight onto the control object
|
|
# with $control->$command(...). A monitor's actions are configured separately
|
|
# from its control protocol, so nothing stops a LightOn action pointing at a
|
|
# protocol that has no lightOn - which is exactly what swapping a camera for a
|
|
# different make leaves behind. That used to kill the control server with
|
|
# "Can't locate object method"; zmcontrol now checks can() first, so this
|
|
# pins down the behaviour can() must have for that guard to work.
|
|
|
|
require_ok('ZoneMinder::Control');
|
|
require_ok('ZoneMinder::Control::ONVIF');
|
|
require_ok('ZoneMinder::Control::AMLink');
|
|
|
|
# The guard's whole basis: can() must answer honestly for inherited, local and
|
|
# absent methods alike.
|
|
ok(ZoneMinder::Control::ONVIF->can('moveConUp'), 'can() sees a method the protocol defines');
|
|
ok(ZoneMinder::Control::ONVIF->can('open'), 'and one it inherits');
|
|
ok(!ZoneMinder::Control::ONVIF->can('lightOn'),
|
|
'ONVIF has no lightOn - the case that took the control server down');
|
|
ok(!ZoneMinder::Control::ONVIF->can('no_such_command_at_all'),
|
|
'and an invented name is not claimed');
|
|
|
|
# AMLink does have the light commands, so the guard must not block them.
|
|
ok(ZoneMinder::Control::AMLink->can('lightOn'), 'AMLink still offers lightOn');
|
|
ok(ZoneMinder::Control::AMLink->can('lightOff'), 'and lightOff');
|
|
|
|
# can() must work on an instance, not just the class, since that is how
|
|
# zmcontrol holds the control object.
|
|
my $obj = bless {}, 'ZoneMinder::Control::ONVIF';
|
|
ok($obj->can('moveConUp'), 'can() works on a blessed instance too');
|
|
ok(!$obj->can('lightOn'), 'and still refuses the missing one');
|
|
|
|
# A command name is taken from json off a socket, so it can be anything.
|
|
# can() must not be fooled into dispatching something dangerous.
|
|
ok(!ZoneMinder::Control::ONVIF->can(''), 'an empty command name is not a method');
|
|
ok(!ZoneMinder::Control::ONVIF->can('0'), 'nor is "0"');
|