The strip cuts the message at the "Log Extract:" marker, and got was declared $256 - so a message whose text pushed the marker past 256 characters was never stripped, and the exact comparison then failed on the escaped tail. got is now the same width as line ($32767). Covered by a new case in mpe_assert_abort.test.sas: an abort whose message runs past 256 characters, asserted in full. It fails against the $256 buffer and passes once got is widened, so the width is pinned rather than assumed. mpe_assert_abort: PASS, full suite 64/64, rebuilt with sasjs cbd.
115 lines
3.9 KiB
SAS
115 lines
3.9 KiB
SAS
/**
|
|
@file
|
|
@brief Asserts that a service returned a sasjsAbort object
|
|
@details Reads the child's response as text and records a PASS when it carries
|
|
a sasjsAbort object, which is what mp_abort leaves in the webout when a service
|
|
rejects its input. When msg is supplied the MSG value inside that object must
|
|
match it, so the assertion proves the service aborted for the expected reason
|
|
rather than for any reason at all.
|
|
|
|
The response is scanned a line at a time and only the first MSG that follows
|
|
the sasjsAbort marker is taken: a single 32767 buffer both truncated longer
|
|
responses and, with a leading `.*`, returned the last MSG in the text rather
|
|
than the abort's own.
|
|
|
|
An unassigned outref (a child that died before writing a response) records a
|
|
FAIL rather than letting the data step fail on an unassigned fileref.
|
|
|
|
Usage:
|
|
|
|
%mpe_execute(&_program,
|
|
inputfiles=&f1:sascontroltable,
|
|
outref=web1,
|
|
outstatus=work.ab1,
|
|
failfast=0
|
|
)
|
|
%mpe_assert_abort(
|
|
desc=An invalid libds aborts the service,
|
|
outref=web1,
|
|
msg=Invalid libds
|
|
)
|
|
|
|
@param [in] desc The description recorded in the test results
|
|
@param [in] outref The fileref given to %mx_execute, holding the response
|
|
@param [in] msg= (0) Expected MSG value in the sasjsAbort object. 0 accepts
|
|
any abort message.
|
|
@param [out] outds= (work.test_results) Results dataset
|
|
|
|
<h4> SAS Macros </h4>
|
|
@li mp_assert.sas
|
|
|
|
**/
|
|
|
|
%macro mpe_assert_abort(desc, outref, msg=0, outds=work.test_results);
|
|
%local ok seen abortseen;
|
|
%let ok=0;
|
|
%let seen=;
|
|
%let abortseen=0;
|
|
|
|
%if %sysfunc(fileref(&outref))>0 %then %do;
|
|
%put %str(WARN)ING: &sysmacroname: fileref &outref is not assigned - the child left no response to read;
|
|
%end;
|
|
%else %if %sysfunc(fileexist(%sysfunc(pathname(&outref)))) ne 1 %then %do;
|
|
/* the fileref exists but nothing was written to it: a child that aborted
|
|
before it produced a response. Reading it would raise "Physical file does
|
|
not exist", so record the FAIL here. */
|
|
%put %str(WARN)ING: &sysmacroname: &outref has no response written to it - the child produced nothing;
|
|
%end;
|
|
%else %do;
|
|
data _null_;
|
|
/* got is the same width as line: the strip of the appended log extract can
|
|
only fire if the whole message reached the buffer, and a hook message can
|
|
run past 256 characters */
|
|
length line $32767 got $32767;
|
|
retain prxid 0 inabort 0 found 0 abortseen 0;
|
|
if _n_=1 then prxid=prxparse('/"MSG" *: *"([^"]*)"/');
|
|
infile &outref end=eof lrecl=32767;
|
|
do while(not eof);
|
|
input;
|
|
line=_infile_;
|
|
if index(line,'sasjsAbort')>0 then do;
|
|
abortseen=1;
|
|
inabort=1;
|
|
end;
|
|
/* first MSG at or after the abort marker - stops at the first found */
|
|
if inabort=1 and found=0 then do;
|
|
if prxmatch(prxid,line)>0 then do;
|
|
got=prxposn(prxid,1,line);
|
|
found=1;
|
|
end;
|
|
end;
|
|
end;
|
|
call symputx('abortseen',abortseen,'l');
|
|
/* mp_abort appends "Log Extract:" and the surrounding log to the message it
|
|
returns. Compare the message the hook raised, not the diagnostic tail - so
|
|
the expectation stays an exact match. */
|
|
if index(got,'Log Extract:')>0 then do;
|
|
got=substr(got,1,index(got,'Log Extract:')-1);
|
|
/* drop the escaped newlines the marker was preceded by - \n pairs, plus
|
|
stray backslashes where the response is JSON inside JSON */
|
|
do while(length(got)>0);
|
|
if length(got)>=2 and substr(got,length(got)-1,2)='\n' then
|
|
got=substr(got,1,length(got)-2);
|
|
else if substr(got,length(got),1)='\' then
|
|
got=substr(got,1,length(got)-1);
|
|
else leave;
|
|
end;
|
|
end;
|
|
if found=1 then call symputx('seen',got,'l');
|
|
stop;
|
|
run;
|
|
%end;
|
|
|
|
%if &abortseen=1 %then %do;
|
|
%if "%superq(msg)"="0" %then %let ok=1;
|
|
%else %if "&seen"="%superq(msg)" %then %let ok=1;
|
|
%end;
|
|
%if "&seen" ne "" %then %put NOTE: &sysmacroname: sasjsAbort MSG=&seen;
|
|
|
|
%mp_assert(
|
|
iftrue=(&ok=1),
|
|
desc=&desc,
|
|
outds=&outds
|
|
)
|
|
%mend mpe_assert_abort;
|