!******************************************************************************!
! Basic test of HTTPSERV (defaults to listening on any available port )
!
! Author  : J. Czechowski IV, Neon Ngo
!******************************************************************************!
startmacro l:port1[0] l:port2[0]
  switch INTERACTIVE interAct GET DEF=TRUE  SDEF=TRUE
  switch BASELINE    baseline GET DEF=FALSE SDEF=TRUE
  switch DEBUG       debug    GET DEF=FALSE SDEF=TRUE

  call setDatDir

  set msgTot    6                    ! Total number of messages
  set msgNum    {HS1=0,HS2=0}        ! Last message number (key mstches /ID=)

  set expMsg    {1={NAME="HTTPGET",  INFO=0, DATA={num=123,str="hello world",txt="foo"}, POSTDATA=""},&
                 2={NAME="HTTPGET",  INFO=0, DATA={num=123,str="hello world",txt="foo"}, POSTDATA=""},&
                 3={NAME="HTTPPOST", INFO=0, DATA={num=123,str="hello world",txt="foo"}, POSTDATA=""},&
                 4={NAME="HTTPPOST", INFO=0, DATA={num=123,str="hello world",txt="bar"}, POSTDATA="MyPostData"},&
                 5={NAME="HTTPGET",  INFO=0, DATA={file="^{datDir}.apenny.prm"},       POSTDATA=""},&
                 6={NAME="HTTPGET",  INFO=0, DATA={num=123.4,file="^{datDir}.airports.csv"},     POSTDATA=""} }

  set inNeXtOpt TEST("^{reg.shell.class}",eqs,"class nxm.sys.libxm.XmShell")

  pipe init
    httpserv/ID=hs1/MSGID=main/MNAME="mymacro"/AUXLIST="*" port1 ^{datDirSlash} "dat"
    httpserv/ID=hs2/MSGID=main/MNAME="/"                   port2
    res port1 reg.hs1.port
    res port2 reg.hs2.port

    call testAccessingRootURL

    ! test case for BUG 2112 HPAGE: readPost(..) is very slow
    call    testLargePostRequest "http://localhost:^{port1}"

    call    testFileAccess {1="http://localhost:^{port1}"}         ! hs1 only (no file access on hs2)
    call/bg testHttpQuery  {1="http://localhost:^{port1}/mymacro",2="http://localhost:^{port2}/"}
    if inNeXtOpt isFALSE then
      call  testSpecAuxAccess
    endif

  pipe off

  call testPortRange
  if interAct isTRUE AND baseline isTRUE then
    %test_httpserv_interactive/interactive=^interAct
  endif

endmacro

!******************************************************************************!
procedure processMessage m:msg
  if msg.name eqs "MAIN" then
    assert/text="^reg.main.name: user indicated" msg.data eqs "PASS"
    pipe stop
  endif

  if msg.name eqs "DONE" then
    foreach key inTable msgNum
      assert/text="^reg.main.name: Got expected number of messages for ^{key}" msgTot eq msgNum.^{key}
    endfor
    pipe stop
  else
    calc L:msgNum.^{msg.fid} msgNum.^{msg.fid} 1 +
    set L:n msgNum.^{msg.fid}
    if expMsg.^{n} REXISTS then
      set exp expMsg.^{n}.data
      set act msg.data.parameters
      assert/text="^reg.main.name: ^{n}. Got expected message (NAME)"       expMsg.^{n}.name eqs msg.name
      assert/text="^reg.main.name: ^{n}. Got expected message (INFO)"       expMsg.^{n}.info eq  msg.info
      assert/text="^reg.main.name: ^{n}. Got expected message (NUM PARAMS)" exp.getSize      eq  act.getSize
      foreach key inTable exp

        ! -- Test case for Bug 176 ".prm" should not be added to HTTP requests
        if key NEQS "FILE" then   ! skip for ?file= (since these should have .[prm|csv] extensions)
          set str "^{act.^{key}}"
          invoke endwithprm str.endsWith(".prm")
          assert/text="^reg.main.name: ^{n}. Request does not have extraneous .prm added to it" endwithprm isFalse
        endif
        ! -- end of test case for Bug 176

        invoke isNum nxm.sys.lib.StringUtil.isNumber(exp.^{key})
        if isNum then
          assert/text="^reg.main.name: ^{n}. Got expected message (PARAM ^{key})" exp.^{key} eq  act.^{key}
        else
          assert/text="^reg.main.name: ^{n}. Got expected message (PARAM ^{key})" exp.^{key} eqs act.^{key}
        endif
      endfor
      if expMsg.^{n}.postdata neqs "" then
        invoke postData   msg.data.socket.postData("data")
        invoke postString postData.getDataString()
        assert/text="^reg.main.name: ^{n}. Got expected message (POST DATA)" expMsg.^{n}.postData eqs postString
      endif
    else
      assert/text="^reg.main.name: ^{n}. Got unexpected message ^msg" fail
    endif
  endif

  if msg.name eqss "HTTP" then
    set socket msg.data.socket
    set params msg.data.parameters
    if debug then say "^reg.main.name: Got ^msg.name request, URI= ^socket.uri"
    assert/text="^reg.main.name: msg.data.socket has URI" socket.uri rexists

    if msg.data.parameters.file rexists then
      invoke,,socket.writeFile(this, msg.data.parameters.file)
    else
      invoke,,socket.setContentType("text/plain")
      invoke,,socket.openSocket()
      invoke,,socket.write("Got request with: ")
      invoke,,socket.writeln(params)
      invoke,,socket.closeSocket()
    endif
  endif
return

!******************************************************************************!
procedure processException m:emsg
  if debug then say "Got exception: emsg=^emsg name=^emsg.name info=^emsg.info data=^emsg.data"
  if emsg.data.rootCause rexists then
    res msg emsg.data.rootCause
  else
    res msg emsg.data
  endif
  assert/text="^reg.main.name: got exception: ^msg" FALSE
return

!******************************************************************************!
! Set the dat directory
!******************************************************************************!
procedure setDatDir
  invoke nxmMajor env.nmversion.subString(0,1)
  invoke major java.lang.Integer.valueOf(nxmMajor)
  if major GE 4 then
    invoke s:datDir           nxm.sys.test.DatLocator.getDatDirLocation()
    invoke s:datDirSlash      nxm.sys.test.DatLocator.getDatDirSlashLocation()
    invoke z:sysDatFull       nxm.sys.test.DatLocator.sysDatFull()
    invoke z:sysTestDatExists nxm.sys.test.DatLocator.sysTestDatExists()
  else
    set s:datDir           "nxm.sys.dat"
    set s:datDirSlash      "nxm/sys/dat"
    set z:sysDatFull       true
    set z:sysTestDatExists false
  endif
return

!******************************************************************************!
! Run basic file-access tests
procedure testFileAccess t:urls
  if ^{env.NMROOT} EQS "classpath:" then
    info "SKIPPING ^reg.main.name At this time, we are unable to serve up directories contained within a jar file. May need to copy the files out of the jar and run"
    return;
  endif
  foreach url inTable/v urls
    assert/text="HTTPSERV Got 404 Not Found Status Code"    ^{url}/xxx/test404.xxx{exist=status} NFEXISTS
    assert/text="HTTPSERV Remote connection to /"           ^{url}/{exist=status} FEXISTS
    assert/text="HTTPSERV Remote connection to NMROOT"      ^{datDir}.apenny.prm FEQ/B "^{url}/nmroot/^{datDirSlash}/apenny.prm"
    assert/text="HTTPSERV Remote connection to DAT"         ^{datDir}.apenny.prm FEQ/B "^{url}/dat/apenny.prm"

    if sysTestDatExists then
      warn "TODO figure out why read named AUXes tests fails for nxm.sys.test.dat"
    ! cannot read named AUXes in NeXtOpt (inside X-Midas)
    elseif inNeXtOpt isFalse then
      assert/text="HTTPSERV Got 404 Not Found Status Code for HEAD request" ^{url}/Files/DAT/test404.xxx NFEXISTS
      ! this should follow the above HEAD request for 404 status code, so show that the above does NOT return content back
      assert/text="HTTPSERV Remote connection to /Files/DAT/" "^{datDir}.apenny.prm" FEQ/B "^{url}/Files/DAT/apenny.prm"
    endif

    ! test case for Bug 1986
    file copy/f "^{url}/Files/" ram:temp_bug1986.txt{FG=TXT}
    status ram:temp_bug1986.txt size=contentsize
    assert/text="HTTPSERV Remote connection to /Files/" contentsize GT 1

  endfor
return

!******************************************************************************!
! Run automated query tests -- must be called with /BG
subroutine testHttpQuery t:urls
  foreach url inTable/v urls
    file copy/f "^{url}?num=123&str=hello+world&txt=foo"                                  ram:temp_auto{FG=TXT}
    file copy/f "^{url}?num=123&str=hello+world&txt=foo{METHOD=GET}"                      ram:temp_get{FG=TXT}
    file copy/f "^{url}?num=123&str=hello+world&txt=foo{METHOD=POST}"                     ram:temp_post{FG=TXT}
    file copy/f "^{url}?num=123&str=hello+world&txt=bar{METHOD=POST,POSTDATA=MyPostData}" ram:temp_post2{FG=TXT}
    file copy/f "^{url}?file=^{datDir}.apenny.prm"                                        ram:temp_apenny{FG=PRM}
    file copy/f "^{url}?num=123%2E4&file=^{datDir}.airports.csv"                          ram:temp_airports{FG=CSV}
  endfor
  message send main NAME=DONE
return

!******************************************************************************!
! test case for Bug 2112 HPAGE: readPost(..) is very slow
! To see performance problem, postSize should be 4K or greater, it should complete
! in less than one second, but I will default timeout to ten seconds for slower machines.
!******************************************************************************!
procedure testLargePostRequest S:url L:postSize[10k] D:timeout[10]
  ! create medium size String for posting to HTTPSERV of postSize
  sedit "test post data for BUG 2112 HPage.readPost(..) is very slow" postStr PADRight postSize "."

  file copy/f url{METHOD="POST",POSTMIME="text",POSTDATA="^postStr",TIMEOUT=^timeout} ram:temp_test_medium_post.txt
  assert/text="^reg.main.name: Got response to POST request with ^postSize post data" ram:temp_test_medium_post.txt FEXISTS
return

!******************************************************************************!
! test case for BUG 1898 (handle root URL properly, e.g. http://hostname/ or
! http://hostname:port/
!******************************************************************************!
procedure testAccessingRootURL
  set rooturl "http://localhost:^{port1}/"
  set destfile "ram:test_httpserv_rooturl.html"
  file copy/f ^rooturl destfile
  assert/text="^reg.main.name: handle root URL: ^rooturl" destfile FEXISTS
  assert/text="^reg.main.name: HEAD request for / URL: ^rooturl" ^{rooturl}{exist=status} FEXISTS
return

!******************************************************************************!
! test case for BUG 2416 HTTPSERV: add port range switch (/PRANGE=)
procedure testPortRange
  httpserv/id=hs1/bg 0
  httpserv/id=hs2/bg/prange=10 reg.hs1.port
  assert/text="^reg.main.name: prereq for /prange (1st HTTPSERV started on ^reg.hs1.port)" (reg.hs1 rexists) AND (reg.hs1.port > 0)
  assert/text="^reg.main.name: /prange (2nd HTTPSERV started)" (reg.hs2 rexists) AND (reg.hs2.port > 0)
  assert/text="^reg.main.name: /prange (2nd HTTPSERV port ^reg.hs2.port > ^reg.hs1.port)"  reg.hs2.port > reg.hs1.port
  invoke ,, reg.hs1.stopThread()
  invoke ,, reg.hs2.stopThread()
return

!******************************************************************************!
! test case for BUG 2574 HTTPSERV: AUX served up without directory listing / HServer updates
procedure testSpecAuxAccess
  file NAME nxmsysjar (^{env.nmroot},jars) nxm-sys.jar
  if nxmsysjar nfexists then
    warn "^{nxmsysjar} does not exist. Did you 'MAKE JAR SYS'? Skipping testSpecAuxAccess test case."
    return
  endif

  aux/store
  set aux.jar1 "jar:^{nxmsysjar}!/nxm/sys/dat/"
  httpserv/id=hs11 port=0 /auxlist="JAR1" /bg

  set aux.125 "http://localhost:^{reg.hs11.port}/Files/JAR1/"
  assert/text="^reg.main.name: find files in special AUX" "^{datDir}.apenny.prm" feq "apenny.prm{aux=125}"

  invoke ,, reg.hs11.stopThread()

  aux/restore
return
