!******************************************************************************!
! Test case for PLOT Pipe Restarts
!
! - Tests for proper number of lines to be copied between buffer and screen buffer
!   when pipe is restarting (to avoid ArrayIndexOutOfBounds caused by attempting
!    to write beyond the end of the screen buffer)
! - To test for resource/memory leak with pipe restarts. Reduce JVM's max memory
!   so that the OutOfMemoryError occurs sooner, e.g.
!     setenv NM_USER_JVM_FLAGS "-Xmx16m"
!     nmstart (MUST start new NeXtMidas session for it to take effect)
!
! Note: This test is designed to run as an overnight (or 100 hour) test in order to
!       detect memory leaks, but can be run as a 3 minute test to detect the 
!       ArrayIndexOutOfBoundsException
!
! @bug      2991 PLOT: Raster plot crashes
! @since    NeXtMidas 3.7.0
! @see      related test cases: test_plot_framesize_updates and test_plot_openfile_invoke
! @author:  Neon Ngo / Jeanette McCall
!******************************************************************************!
startmacro L:minFFT[1024] L:lps[128] l:lpb[16]
  switch INTERACTIVE   interAct         GET DEF=TRUE  SDEF=TRUE ! for normal interactive test(s)
  switch COREGRAPHICS  coreGraphics     GET DEF=FALSE SDEF=TRUE ! for a quick check of graphics - more extreme tests - since 3.8.1
  switch INTERVAL      interval         GET DEF=0.2             ! time in between invoking openFile(..)
  switch NUMFFTSIZES   numfftsizes      GET DEF=2               ! how many fft sizes to cycle through
  switch DURATION      duration         GET DEF=360000          ! how long to run test case for (seconds)
  switch REPORT        reporthours      GET DEF=0.1             ! report every 6 minutes
  switch PIPEREADERS   L:numPipeReaders GET DEF=20              ! number of addition pipe readers of _FFT pipe

  set secondsPerHour   3600  ! constant
  set secondsPerMinute   60  ! constant
  set mult_FFTSize        0  ! used to cycle through frame sizes

  timex "2017:01:01::00:00:00" sec=tsec

  if interAct or coreGraphics then

    calc timeInMinutes duration secondsPerMinute /
    calc timeInHours   duration secondsPerHour /
    res timeruns "^timeInHours hours"
    if duration < secondsPerHour then
      res timeruns "^timeInMinutes minutes"
    endif

    calc L:numPipeReaders numPipeReaders 28 min  ! cap readers to give room for plot and status of _fft pipe
    set instructions "This runs automatically for ^timeruns (flagging any exception as FAILURE). &
                      This test is primarily designed to run in an overnight / background test, &
                      but is also run in shortened form in regular baseline testing.\n\n&
                      Updating via pipe restarts. Running NeXtMidas ^ENV.NMVERSION"

    timer set
    pipe on
      panel/msgid=MAIN/setup/controls=gc
      gcontrol label macro "Test MACRO"
      gcontrol menu  main "Exit with Status =" "PASS,FAIL" TABLE={ItemColors={PASS="GREEN",FAIL="RED"}} /tleft

      gcontrol text   idtext       "Instructions"    instructions 24 12     /title
      gcontrol dval   dInterval    "Swap interval seconds "    interval    0 60 0.1 /FMT="#0.###"
      gcontrol lval   lnumfftsizes "FFT Sizes in cycle" numfftsizes  0 16 4 /FMT="#0"
      gcontrol dval   dReport      "Report interval hours " reporthours 0 10 0.1 /FMT="#0.###"

      waveform/id=testsine _wave form="SF" elem=inf shape=sine start=^tsec
      fft _wave _fft{maxoutlets=31} nfft=^minFFT over=0
      plot/id=idplot _fft /LPS=^lps /LPB=^lpb
      do ii 1 numPipeReaders
        noop/id=noop_^{ii} _fft _noop^{ii}
      enddo

      gcontrol/id=pmon1 pipemon pmon1 _FFT

      ! three timers, second one to stop test case
      set this.timers 3

      ! set timer to change plot
      set this.timer(0) interval

      ! set timer to exit test case
      set this.timer(1) duration

      ! set timer to report every status
      calc reportseconds reporthours secondsPerHour *
      set this.timer(2) reportseconds
    pipe off
    timer elapse

  endif
endmacro

!******************************************************************************!
! Main process message for this macro. Should be right after the ENDMACRO.
!******************************************************************************!
procedure processMessage m:msg
  if msg.name eqs "MAIN" then
    assert/text="^reg.main.name: User indicated tests" msg.data eqss "PASS"
    pipe stop

  elseif msg.name eqs "TIMER" then
    timer elapse elapsedTime
    calc timeInHours elapsedTime secondsPerHour /
    ! 2nd timer is to stop test case
    if msg.info eq 1 then
      pipe stop

    ! 3rd timer for reporting total/duration time of run
    elseif msg.info eq 2 then
      say "test case has run ^timeInHours hours :  minFFT=^minFFT LPS=^lps LPB=^lpb swap interval=^interval # FFT sizes in cycle:^numfftsizes"

      if ram._wave.getpipe.outlets > 1 then
        warn "Expected only 1 reader on _wave pipe, but there are ^{ram._wave.getpipe.outlets}! after ^elapsedTime seconds."
      endif

    ! timer to switch frame size
    else
      if reg.idplot nrexists then
        assert/text="^reg.main.name: PLOT died! after ^elapsedTime seconds (~^timeInHours hours)." FAIL
        set this.timer(0) 0.0
      endif

      ! cycle through numfscycle frame sizes starting with minimum and ending with minimum * 4
      calc mult_FFTSize mult_FFTSize 1 +
      calc fft_size minFFT mult_FFTSize *
      calc mult_FFTSize mult_FFTSize ^numfftsizes mod

      res reg.fft.nfft fft_size
      !res reg.fft.nfft

    endif

  elseif msg.name eqs "DINTERVAL" then
    set interval msg.data
    set this.timer(0) interval

  elseif msg.name eqs "DREPORT" then
    res reporthours msg.data
    calc reportseconds reporthours secondsPerHour *
    set this.timer(2) reportseconds

  elseif msg.name eqs "LNUMFFTSIZES" then
    res numfftsizes msg.data

  else
    say "Unhandled message name: ^msg.name from fid: ^msg.fid data: ^msg.data"
  endif
return

!******************************************************************************!
! If an unexpected exception is caught, mark test as failed, unless it is expected
!******************************************************************************!
procedure processException m:emsg
  if expectedException REXISTS then
    assert/text="^reg.main.name: Expected ERROR starts with: ^{expectedException}" expectedException EQSS emsg.data.message
    remove expectedException
  else
    assert/text="^reg.main.name: Caught unexpected exception ^{emsg.data}" "FALSE" isTrue
    if "Trace" SUBS ENV.DEBUG then invoke ,, emsg.data.printStackTrace()
  endif
return
