2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 00:36:25 +00:00

98_FhemTestUtils.pm: Fhem Test Utils and test framework (Forum #111061)

git-svn-id: https://svn.fhem.de/fhem/trunk@21926 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2020-05-13 10:27:43 +00:00
parent 2e16ea71c6
commit 3978ce1663
9 changed files with 217 additions and 7 deletions

1
fhem/.proverc Normal file
View File

@ -0,0 +1 @@
--exec 'perl fhem.pl -t'

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- feature: module test framework (fhem.pl -t / FhemTestUtils)
- change: 00_MYSENSORS: apply some PBP recommendations,
integrate libs from fib/Device/MySensors
- feature: 10_MYSENSORS_DEVICE: PBP, see 00_MYSENSORS;

View File

@ -0,0 +1,130 @@
##############################################
# $Id$
package main;
use strict;
use warnings;
my @events;
my @logs;
sub FhemTestUtils_gotLog($);
sub FhemTestUtils_resetLogs();
sub FhemTestUtils_gotEvent($);
sub FhemTestUtils_resetEvents();
sub
FhemTestUtils_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "FhemTestUtils_Define";
$hash->{NotifyFn} = "FhemTestUtils_Notify";
}
sub
FhemTestUtils_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
return "Wrong syntax: use define <name> dummy" if(int(@a) != 2);
$logInform{$a[0]} = sub() { push @logs, $_[1] };
return undef;
}
sub
FhemTestUtils_Notify($$)
{
my ($ntfy, $dev) = @_;
my $events = deviceEvents($dev, 0);
my $n = $dev->{NAME};
#map { print "$n:$_\n" } @{$events};
return if(!$events); # Some previous notify deleted the array.
push @events, map { "$n:$_" } @{$events};
return undef;
}
sub
FhemTestUtils_gotEvent($)
{
my ($arg) = @_;
return grep /$arg/,@events;
}
sub
FhemTestUtils_resetEvents()
{
@events=();
}
sub
FhemTestUtils_gotLog($)
{
my ($arg) = @_;
return grep /$arg/,@logs;
}
sub
FhemTestUtils_resetLogs()
{
@logs=();
}
1;
=pod
=item helper
=item summary Utility functions for testing FHEM modules
=item summary_DE Hilfsfunktionen, um FHEM Module zu testen
=begin html
<a name="FhemTestUtils"></a>
<h3>FhemTestUtils</h3>
<ul>
An instance of this module will be automatically defined, if fhem.pl is
called with the -t option.
The module will collect all events and Log messages, so a test program is
able to check, if an event or log message was generated.<br>
Available functions:
<ul>
<li>FhemTestUtils_gotEvent($)<br>
Return the events matching the regexp argument (with grep).
</li>
<li>FhemTestUtils_gotLog($)<br>
Return the logs matching the regexp argument (with grep).
Note, that loglevel filtering with verbose ist still active.
</li>
<li>FhemTestUtils_resetEvents()<br>
Reset the internal event buffer.
</li>
<li>FhemTestUtils_resetLogs()<br>
Reset the internal log buffer.
</li>
</ul>
<br><br>
<a name="FhemTestUtilsdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; FhemTestUtils</code>
</ul>
<br>
<a name="FhemTestUtilsset"></a>
<b>Set</b> <ul>N/A</ul><br>
<a name="FhemTestUtilsget"></a>
<b>Get</b> <ul>N/A</ul><br>
<a name="FhemTestUtilsattr"></a>
<b>Attributes</b> <ul>N/A</ul><br>
</ul>
=end html
=cut

View File

@ -480,6 +480,7 @@ FHEM/98_DSBMobile KernSani https://forum.fhem.de/index.php/topic,107104
FHEM/98_expandJSON.pm dev0 Unterstützende Dienste
FHEM/98_feels_like.pm hotbso Wettermodule
FHEM/98_fhemdebug.pm rudolfkoenig Sonstiges
FHEM/98_FhemTestUtils.pm rudolfkoenig Development
FHEM/98_fheminfo.pm betateilchen Sonstiges
FHEM/98_freezemon KernSani Unterstützende Dienste
FHEM/98_FReplacer.pm StefanStrobel Sonstiges

View File

@ -127,6 +127,7 @@ sub devspec2array($;$$);
sub doGlobalDef($);
sub escapeLogLine($);
sub evalStateFormat($);
sub execFhemTestFile();
sub fhem($@);
sub fhemTimeGm($$$$$$);
sub fhemTimeLocal($$$$$$);
@ -143,6 +144,8 @@ sub latin1ToUtf8($);
sub myrename($$$);
sub notifyRegexpChanged($$);
sub parseParams($;$$$);
sub prepareFhemTestFile();
sub execFhemTestFile();
sub perlSyntaxCheck($%);
sub readingsBeginUpdate($);
sub readingsBulkUpdate($$$@);
@ -241,6 +244,7 @@ use vars qw($cvsid); # used in 98_version.pm
use vars qw($devcount); # Maximum device number, used for storing
use vars qw($featurelevel);
use vars qw($fhemForked); # 1 in a fhemFork()'ed process, else undef
use vars qw($fhemTestFile); # file to include if -t is specified
use vars qw($fhem_started); # used for uptime calculation
use vars qw($haveInet6); # Using INET6
use vars qw($init_done); #
@ -478,14 +482,16 @@ my %ra = (
# Start the program
my $fhemdebug;
$fhemdebug = shift @ARGV if($ARGV[0] eq "-d");
prepareFhemTestFile();
if(int(@ARGV) < 1) {
print "Usage:\n";
print "as server: fhem configfile\n";
print "as client: fhem [host:]port cmd cmd cmd...\n";
print "as server: perl fhem.pl [-d] {<configfile>|configDb}\n";
print "as client: perl fhem.pl [host:]port cmd cmd cmd...\n";
print "testing: perl fhem.pl -t <testfile>.t\n";
if($^O =~ m/Win/) {
print "install as windows service: fhem.pl configfile -i\n";
print "uninstall the windows service: fhem.pl -u\n";
print "install as windows service: perl fhem.pl configfile -i\n";
print "uninstall the windows service: perl fhem.pl -u\n";
}
exit(1);
}
@ -569,8 +575,9 @@ if(configDBUsed()) {
# As newer Linux versions reset serial parameters after fork, we parse the
# config file after the fork. But we need some global attr parameters before, so we
# read them here.
# config file after the fork. But we need some global attr parameters before,
# so we read them here. FHEM_GLOBALATTR is for docker, as it needs to overwrite
# fhem.cfg
my (undef, $globalAttrFromEnv) = parseParams($ENV{FHEM_GLOBALATTR});
setGlobalAttrBeforeFork($attr{global}{configfile});
applyGlobalAttrFromEnv();
@ -661,6 +668,7 @@ my $osuser = "os:$^O user:".(getlogin || getpwuid($<) || "unknown");
Log 0, "Featurelevel: $featurelevel";
Log 0, "Server started with ".int(keys %defs).
" defined entities ($attr{global}{version} perl:$] $osuser pid:$$)";
execFhemTestFile();
################################################
# Main Loop
@ -990,7 +998,7 @@ Log3($$$)
no strict "refs";
foreach my $li (keys %logInform) {
if($defs{$li}) {
if($defs{$li}) { # Function wont be called for WARNING, don't know why
&{$logInform{$li}}($li, "$tim $loglevel : $text");
} else {
delete $logInform{$li};
@ -4378,6 +4386,7 @@ setGlobalAttrBeforeFork($)
next if($l !~ m/^attr\s+global\s+([^\s]+)\s+(.*)$/);
AnalyzeCommand(undef, $l);
}
CommandAttr(undef, "global modpath .") if(!AttrVal("global","modpath",""));
}
sub
@ -6070,4 +6079,29 @@ applyGlobalAttrFromEnv()
}
}
# set the test config file: either the corresponding X.cfg, or fhem.cfg
sub
prepareFhemTestFile()
{
return if($ARGV[0] ne "-t" || @ARGV < 2);
shift @ARGV;
return if($ARGV[0] !~ m,^(.*?)([^/]+)\.t$,);
my ($dir, $fileBase) = ($1, $2);
$fhemTestFile = $ARGV[0];
$ARGV[0] = "${dir}fhem.cfg" if(-r "${dir}fhem.cfg");
$ARGV[0] = "$dir$fileBase.cfg" if(-r "$dir$fileBase.cfg");
}
sub
execFhemTestFile()
{
return if(!$fhemTestFile);
$attr{global}{autosave} = 0;
AnalyzeCommand(undef, "define .ftu FhemTestUtils")
if(!grep { $defs{$_}{TYPE} eq "FhemTestUtils" } keys %defs);
InternalTimer(1, sub { require $fhemTestFile }, 0 ) if($fhemTestFile);
}
1;

View File

@ -0,0 +1,15 @@
# Simple test. NOTE: exit(0) is necessary
use strict;
use warnings;
use Test::More;
{ MQTT2_SERVER_ReadDebug($defs{m2s}, '0(12)(0)(5)helloworld') }
is(FhemTestUtils_gotLog("ERROR:.*bogus data"), 0, "Correct MQTT message");
FhemTestUtils_resetLogs();
{MQTT2_SERVER_ReadDebug($defs{m2s}, '(162)(50)(164)(252)(0).7c:2f:80:97:b0:98/GenericAc(130)(26)(212)4(0)(21)BLE2MQTT/OTA/')}
is(FhemTestUtils_gotLog("ERROR:.*bogus data"), 1, "Bogus message, as expected");
done_testing;
exit(0);
1;

View File

@ -0,0 +1,2 @@
define m2s MQTT2_SERVER 1883
define ac autocreate

View File

@ -0,0 +1,25 @@
# More complex test, with external program and delayed log/event checking
# Note: exit(0) must be called in the delayed code.
use strict;
use warnings;
use Test::More;
my $usage = `mosquitto_pub 2>&1`;
if(!$usage) { # mosquitto not installed
ok(1);
done_testing;
exit(0);
}
fhem('"mosquitto_pub -i test -t hallo -m world"');
InternalTimer(time()+1, sub() {
is(FhemTestUtils_gotLog(
"autocreate: define MQTT2_test MQTT2_DEVICE test m2s"), 1,
"autocreate log");
is(FhemTestUtils_gotEvent("MQTT2_test:hallo: world"), 1,
"autocreate event");
done_testing;
exit(0);
}, 0);
1;

View File

@ -0,0 +1 @@
define m2s MQTT2_SERVER 1883