diff --git a/base/mp_testservice.sas b/base/mp_testservice.sas index 12e7466..74b3ff6 100644 --- a/base/mp_testservice.sas +++ b/base/mp_testservice.sas @@ -42,6 +42,7 @@ @li mp_binarycopy.sas @li mp_chop.sas @li mp_ds2csv.sas + @li ms_testservice.sas @li mv_getjobresult.sas @li mv_jobflow.sas @@ -270,95 +271,16 @@ filename &webref "&webrefpath"; %end; %else %if &platform=SASJS %then %do; - /* avoid sending bom marker to API */ - %local optval; - %let optval=%sysfunc(getoption(bomfile)); - options nobomfile; - - data _null_; - file &fname0 termstr=crlf; - infile &inref end=eof; - if _n_ = 1 then do; - put "--&boundary."; - put 'Content-Disposition: form-data; name="filePath"'; - put ; - put "&driveloc"; - put "--&boundary"; - put 'Content-Disposition: form-data; name="file"; filename="ignore.sas"'; - put "Content-Type: text/plain"; - put ; - end; - input; - put _infile_; /* add the actual file to be sent */ - if eof then do; - put ; - put "--&boundary--"; - end; - run; - - data _null_; - file &fname1 lrecl=1000; - infile "&_sasjs_tokenfile" lrecl=1000; - input; - put "Content-Type: multipart/form-data; boundary=&boundary"; - put "Authorization: Bearer " _infile_; - run; - - %if &mdebug=1 %then %do; - data _null_; - infile &fname0; - input; - put _infile_; - data _null_; - infile &fname1; - input; - put _infile_; - run; - %end; - - proc http method='POST' in=&fname0 headerin=&fname1 out=&webref - url="&_sasjs_apiserverurl/SASjsApi/drive/file"; - %if &mdebug=1 %then %do; - debug level=1; - %end; - run; - - /* reset options */ - options &optval; - - /* SASjs services have the _webout embedded in wrapper JSON */ - /* Files can also be very large - so use a dedicated macro to chop it out */ - %local matchstr1 matchstr2 chopout1 chopout2; - %let matchstr1={"status":"success","_webout":{; - %let matchst2=},"log":[{; - %let chopout1=&webrefpath._1; - %let chopout2=&webrefpath._2; - - %mp_chop("&webrefpath" - ,matchvar=matchstr1 - ,keep=LAST - ,matchpoint=END - ,offset=-1 - ,outfile="&chopout1" + %ms_testservice(&program + ,inputfiles=&inputfiles + ,inputdatasets=&inputdatasets + ,inputparams=&inputparams + ,debug=&debug ,mdebug=&mdebug + ,outlib=&outlib + ,outref=&outref ) - %mp_chop("&chopout1" - ,matchvar=matchstr2 - ,keep=FIRST - ,matchpoint=START - ,offset=1 - ,outfile="&chopout2" - ,mdebug=&mdebug - ) - - %if &outlib ne 0 %then %do; - libname &outlib json ("&chopout2"); - %end; - %if &outref ne 0 %then %do; - filename &outref "&chopout2"; - %end; - %end; %else %do; %put %str(ERR)OR: Unrecognised platform: &platform; diff --git a/server/ms_testservice.sas b/server/ms_testservice.sas new file mode 100644 index 0000000..16db635 --- /dev/null +++ b/server/ms_testservice.sas @@ -0,0 +1,152 @@ +/** + @file + @brief Will execute a SASjs web service on SASjs Server + @details Prepares the input files and retrieves the resulting datasets from + the response JSON. + + @param [in] program The Stored Program endpoint to test + @param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as + follows: + inputfiles=inref:filename inref2:filename2 + @param [in] inputdatasets= (0) All datasets in this space seperated list are + converted into SASJS-formatted CSVs (see mp_ds2csv.sas) files and added to + the list of `inputfiles` for ingestion. The dataset will be sent with the + same name (no need for a colon modifier). + @param [in] inputparams=(0) A dataset containing name/value pairs in the + following format: + |name:$32|value:$1000| + |---|---| + |stpmacname|some value| + |mustbevalidname|can be anything, oops, %abort!!| + + @param [in] debug= (131) Provide the _debug value to pass to the STP + @param [in] mdebug= (0) Set to 1 to provide macro debugging (this macro) + @param [out] outlib= (0) Output libref to contain the final tables. Set to + 0 if the service output is not in JSON format. + @param [out] outref= (0) Output fileref to create, to contain the full _webout + response. + @param [out] outlogds= (_null_) Set to the name of a dataset to contain the + log. Table format: + |line:$2000| + |---| + |log line 1| + |log line 2| + +

SAS Macros

+ @li mf_getuniquefileref.sas + @li mf_getuniquename.sas + @li mp_abort.sas + @li mp_binarycopy.sas + @li mp_chop.sas + @li mp_ds2csv.sas + @li ms_runstp.sas + +

Related Programs

+ @li mp_testservice.test.sas + + @version 9.4 + @author Allan Bowe + +**/ + +%macro ms_testservice(program, + inputfiles=0, + inputdatasets=0, + inputparams=0, + debug=0, + mdebug=0, + outlib=0, + outref=0, + outlogds=_null_ +)/*/STORE SOURCE*/; +%local dbg fref1 chopout1 chopout2; +%if &mdebug=1 %then %do; + %put &sysmacroname entry vars:; + %put _local_; +%end; +%else %let dbg=*; + +/* convert inputdatasets to filerefs */ +%if "&inputdatasets" ne "0" %then %do; + %if %quote(&inputfiles)=0 %then %let inputfiles=; + %do i=1 %to %sysfunc(countw(&inputdatasets,%str( ))); + %let var=%scan(&inputdatasets,&i,%str( )); + %local dsref&i; + %let dsref&i=%mf_getuniquefileref(); + %mp_ds2csv(&var,outref=&&dsref&i,headerformat=SASJS) + %let inputfiles=&inputfiles &&dsref&i:%scan(&var,-1,.); + %end; +%end; + +/* parse the filerefs - convert to a dataset */ +%let ds1=%mf_getuniquename(); +data &ds1; + length fileref $8 name $32 filename $256 var $300; + webcount=countw("&inputfiles"); + do i=1 to webcount; + var=scan("&inputfiles",i,' '); + fileref=scan(var,1,':'); + name=scan(var,2,':'); + filename=cats(name,'.csv'); + output; + end; +run; + + +/* execute the STP */ +%let fref1=%mf_getuniquefileref(); + +%ms_runstp(&program + ,debug=&debug + ,inputparams=&inputparams + ,inputfiles=&ds1 + ,outref=&fref1 + ,mdebug=&mdebug + ,outlogds=&outlogds +) + + +/* SASjs services have the _webout embedded in wrapper JSON */ +/* Files can also be very large - so use a dedicated macro to chop it out */ +%local matchstr1 matchstr2 ; +%let matchstr1={"status":"success","_webout":{; +%let matchstr2=},"log":[{; +%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1); +%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2); + +%mp_chop("%sysfunc(pathname(&fref1,F))" + ,matchvar=matchstr1 + ,keep=LAST + ,matchpoint=END + ,offset=-1 + ,outfile="&chopout1" + ,mdebug=&mdebug +) + +%mp_chop("&chopout1" + ,matchvar=matchstr2 + ,keep=FIRST + ,matchpoint=START + ,offset=1 + ,outfile="&chopout2" + ,mdebug=&mdebug +) + +%if &outlib ne 0 %then %do; + libname &outlib json "&chopout2"; +%end; +%if &outref ne 0 %then %do; + filename &outref "&chopout2"; +%end; + +%if &mdebug=0 %then %do; + filename &webref clear; + filename &fref1 clear; + filename &fref2 clear; +%end; +%else %do; + %put &sysmacroname exit vars:; + %put _local_; +%end; + +%mend ms_testservice; \ No newline at end of file diff --git a/tests/crossplatform/mp_testservice.test.sas b/tests/crossplatform/mp_testservice.test.sas index 315326d..d52cefc 100644 --- a/tests/crossplatform/mp_testservice.test.sas +++ b/tests/crossplatform/mp_testservice.test.sas @@ -55,37 +55,28 @@ run; outlib=testlib1, outref=test1 ) - -%global test1a test1b test1c test1d; +%let test1=FAIL; data _null_; - infile test1; - input; - putlog _n_ _infile_; - if _infile_=', "somedata1":' then call symputx('test1a','PASS'); - if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then - call symputx('test1b','PASS'); - if _infile_='], "somedata2":' then call symputx('test1c','PASS'); - if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then - call symputx('test1d','PASS'); + set testlib1.somedata1; + if x=1 and y=' t"w"o' and z="Z" then call symputx('test1','PASS'); + putlog (_all_)(=); run; +%let test2=FAIL; +data _null_; + set testlib1.somedata2; + if x=1 and y=' t"w"o' and z="Z" then call symputx('test2','PASS'); + putlog (_all_)(=); +run; + + %mp_assert( - iftrue=(&test1a=PASS), - desc=Test 1 table 1 name, + iftrue=(&test1=PASS), + desc=somedata1 created correctly, outds=work.test_results ) %mp_assert( - iftrue=(&test1b=PASS), - desc=Test 1 table 1 values, + iftrue=(&test2=PASS), + desc=somedata2 created correctly, outds=work.test_results ) -%mp_assert( - iftrue=(&test1c=PASS), - desc=Test 1 table 2 name, - outds=work.test_results -) -%mp_assert( - iftrue=(&test1d=PASS), - desc=Test 1 table 2 values, - outds=work.test_results -) \ No newline at end of file diff --git a/tests/serveronly/ms_testservice.test.sas b/tests/serveronly/ms_testservice.test.sas new file mode 100644 index 0000000..e61f7dc --- /dev/null +++ b/tests/serveronly/ms_testservice.test.sas @@ -0,0 +1,87 @@ +/** + @file + @brief Testing ms_testservice.sas macro + +

SAS Macros

+ @li ms_createwebservice.sas + @li ms_testservice.sas + @li mp_assert.sas + +**/ + +filename ft15f001 temp; +parmcards4; + %put Initialising sendObj: ; + %put _all_; + %webout(FETCH) + %webout(OPEN) + %macro x(); + %if (%symexist(sasjs_tables) and %length(&sasjs_tables)>0) + %then %do i=1 %to %sysfunc(countw(&sasjs_tables)); + %let table=%scan(&sasjs_tables,&i); + %webout(OBJ,&table,missing=STRING) + %end; + %else %do i=1 %to &_webin_file_count; + %webout(OBJ,&&_webin_name&i,missing=STRING) + %end; + %mend x; %x() + %webout(CLOSE) +;;;; +%put creating web service: &mcTestAppLoc/services; +%ms_createwebservice( + path=&mcTestAppLoc/services, + name=sendObj, + mdebug=&sasjs_mdebug +) +%put created web service: &mcTestAppLoc/services; + +%mp_assert( + iftrue=(&syscc=0), + desc=No errors after service creation, + outds=work.test_results +) + +/** + * Test 1 - send a dataset + */ +data work.somedata1 work.somedata2; + x=1; + y=' t"w"o'; + z=.z; + label x='x factor'; + output; +run; + +%ms_testservice(&mcTestAppLoc/services/sendObj, + inputdatasets=work.somedata1 work.somedata2, + debug=log, + mdebug=1, + outlib=testlib1, + outref=test1 +) + +%let test1=FAIL; +data _null_; + set testlib1.somedata1; + if x=1 and y=' t"w"o' and z="Z" then call symputx('test1','PASS'); + putlog (_all_)(=); +run; + +%let test2=FAIL; +data _null_; + set testlib1.somedata2; + if x=1 and y=' t"w"o' and z="Z" then call symputx('test2','PASS'); + putlog (_all_)(=); +run; + + +%mp_assert( + iftrue=(&test1=PASS), + desc=somedata1 created correctly, + outds=work.test_results +) +%mp_assert( + iftrue=(&test2=PASS), + desc=somedata2 created correctly, + outds=work.test_results +)