Project

General

Profile

Bug #9893

LegacyErrorException is not rethrown in processForBody/processBody

Added by Andrei Plugaru over 1 year ago. Updated about 1 year ago.

Status:
Internal Test
Priority:
Normal
Assignee:
Andrei Plugaru
Target version:
-
Start date:
Due date:
% Done:

90%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
production:
No
env_name:
topics:

Related issues

Related to Base Language - Bug #9910: Incorrect Error Handling for ROUTINE-LEVEL ON ERROR UNDO, THROW in FWD ABLUnit Tests New
Related to Base Language - Bug #4602: fixes for OO 4GL and structured error handling Review

History

#1 Updated by Andrei Plugaru over 1 year ago

  • Status changed from New to WIP

While investigating another issue, I found this testcase which has the wrong behaviour in FWD:

block-level on error undo, throw.

def temp-table tt1
field f1 as int
field f2 as int
index idx1 as unique f1 .

def temp-table tt2
field f1 as int
.

create tt1.
tt1.f1 = 1.

create tt2.
tt2.f1 = 1.

create tt1.

procedure p1:
    for each tt2 on error undo, throw: 

    assign
        tt1.f1 = 1
        tt1.f2 = 2.       
     end.

message 'end procedure'.
end.

do on error undo, throw:
    run p1.
    message 'after test'. // FWD
    catch err as Progress.Lang.Error:
        message 'in catch block'. // OE
    end.

end.

The original discussion is #9753, starting in #9753-38.

#2 Updated by Andrei Plugaru over 1 year ago

  • Status changed from WIP to Review
  • reviewer Constantin Asofiei added

The solution is already in 9753a/15849. Constantin, please review it when you are available.

#4 Updated by Vladimir Tsichevski over 1 year ago

  • Related to Bug #9910: Incorrect Error Handling for ROUTINE-LEVEL ON ERROR UNDO, THROW in FWD ABLUnit Tests added

#5 Updated by Constantin Asofiei over 1 year ago

Eduard: please check and advise.

#6 Updated by Eduard Soltan over 1 year ago

I know this one, ValidationError error from batchAssign is propagated as a LegacyError, but another ValidationError error is raised from the call to wa.tm::processValidate in BM.processBody.

It seems ok to me, but looking at the logic in BM.processLegacyError it will either throw the exception further (as LegacyError or ErrorConditionException) or display the error message and leave the block (throw LeaveUnwindException). In either case I think the validation should not happen.

The code will still work when the exception is not re-thrown, since the LeaveUnwindException will be caught by the catch (Throwable thr).

#7 Updated by Eduard Soltan over 1 year ago

Perhaps a more simple approach with a flag in set in DeferredLegacyErrorException and LegacyErrorException, and verified in finally if statement could also suffice.

#8 Updated by Eduard Soltan over 1 year ago

Andrei Plugaru wrote:

The solution is already in 9753a/15849. Constantin, please review it when you are available.

After a discussion with Andrei, I think there is a case that this approach will compromise.

block-level on error undo, throw.

def temp-table tt1
field f1 as int
field f2 as int
index idx1 as unique f1 .

def temp-table tt2
field f1 as int
.

create tt1.
tt1.f1 = 1.

create tt2.
tt2.f1 = 1.

create tt1.

procedure p1:
    for each tt2 on error undo, throw: 
       assign
          tt1.f1 = 1
          tt1.f2 = 2.

        catch ex as Progress.Lang.Error:
           message "CATCH BLOCK".
        end.
    end.
    message 'end procedure'.
end.

do on error undo, throw:
    run p1.
    message 'after test'. // FWD
    catch err as Progress.Lang.Error:
        message 'in catch block'. // OE
    end.

end.

ValidationError error from batchAssign is propagated as a LegacyError, and caught by BM.processForBody. In processLegacyError method because it found a catch block in the current block a LeaveUnwindException will be thrown to execute the CATCH in TM.popScope.

This will make the reason a LeaveUnwindException exception and isNormal method will return true and hence validation will happen again.

#9 Updated by Andrei Plugaru over 1 year ago

I had a conversation with Eduard, and today I continued his implementation and committed it in 9753a/15850

Functionally, the difference from the solution in #9753-48 would be that we will skip validation also in the case when a LegacyErrorException/DeferredLegacyErrorException got to a catch block from BlockManager.processForBody/processBody, but was not rethrown.

I also run fwd tests of a large customer application and got no regressions. Constantin, please take a look.

#10 Updated by Constantin Asofiei about 1 year ago

The changes make sense in 9754a 9753a/15850.

#11 Updated by Andrei Plugaru about 1 year ago

Constantin, can we move on to testing? If yes, I can do the unit tests and fwd tests of a large customer application. Do you think anything else is necessary?

#12 Updated by Constantin Asofiei about 1 year ago

  • Status changed from Review to Internal Test
  • Assignee set to Andrei Plugaru

Andrei Plugaru wrote:

Constantin, can we move on to testing? If yes, I can do the unit tests and fwd tests of a large customer application. Do you think anything else is necessary?

Yes, go ahead. Please also update the %Done.

#13 Updated by Andrei Plugaru about 1 year ago

  • % Done changed from 0 to 100
Test plan:
  1. fwd tests and unit tests [me]
  2. unit tests of large customer application [ai]
  3. unit tests of large customer application [ls]
  4. unit tests of large GUI application [sb]
  5. smoke tests of large GUI application [ab2] ✅

Important: the task branch is 9753a.

#14 Updated by Lorian Sandu about 1 year ago

Harness testing passed!

#15 Updated by Andrei Iacob about 1 year ago

Andrei Plugaru wrote:

unit tests of large customer application [ai]

Passed! ✅

#16 Updated by Andrei Iacob about 1 year ago

Andrei Plugaru wrote:

unit tests of large GUI application [ai]

Passed! ✅

#17 Updated by Andrei Plugaru about 1 year ago

In the large customer application I tested, I discovered a few regressions. At this moment, I am not sure whether the changes in 9753a expose some latent bug or there is problem in my changes. Will investigate this.

#18 Updated by Andrei Plugaru about 1 year ago

  • % Done changed from 100 to 90

I found a smaller recreate of the failing test:

using OEUnit.Assertion.Assert.

routine-level on error undo, throw.

class DuplicationTest:

   method private void setup1(): 

      create t1.
      assign
         t1.f1           = "a" 
         t1.f2 = "b" 
         .
      release t1.

   end method.

      @Before.
   method public void PreTestSetup():
       for each t1:
           delete t1.
           end.
      setup1().
      setup2().

   end method.

   @Test.
   method public void test(): 
      Assert:IsTrue(true).

   end method.

   method private void setup2 (): 

      create t1.
      assign
         t1.f1           = "a" 
                  t1.f2 = "b" 

         .
      release t1.

   end method.

end class.

It's important that the t1 table has an unique index on f1.

When running this in OE, the behaviour is quite strange. This isn't classified as either a failure or success.
By default, in FWD, the same behaviour is preserved. Even though, the test has a failure message, it is not classified either as a failure or success. This is the exact output:

Failures (1):
  FWD Test:TestSuite:DuplicationTest
    ClassSource [className = 'com.goldencode.dataset.DuplicationTest', filePosition = null]
    => org.opentest4j.AssertionFailedError: ** t1 already exists with f1 "a". (132)
       com.goldencode.p2j.oo.lang.SysError.newInstance(SysError.java:151)
       com.goldencode.dataset.DuplicationTest.setup2(DuplicationTest.java:103)
       com.goldencode.dataset.DuplicationTest.setup2(DuplicationTest.java:100)
       com.goldencode.dataset.DuplicationTest.preTestSetup(DuplicationTest.java:83)
       com.goldencode.dataset.DuplicationTest.preTestSetup(DuplicationTest.java:68)

Test run finished after 181 ms
[         3 containers found      ]
[         0 containers skipped    ]
[         3 containers started    ]
[         0 containers aborted    ]
[         2 containers successful ]
[         1 containers failed     ]
[         1 tests found           ]
[         0 tests skipped         ]
[         0 tests started         ]
[         0 tests aborted         ]
[         0 tests successful      ]
[         0 tests failed          ]

However, comparing the old logs of the unit tests of the large customer application, the error message was not present at all. So, I was trying to understand the difference. During debugging, I understood that at some point in the large customer application, a PersistenceException is raised because an unique index was violated. This didn't happen in my small testcase. So, I tried to understand the difference between my env and the one from the large customer application. One curcial difference is that when my database is imported, the indices are not created at the DB level. I am not sure why schema_index_fwd_*.sql isn't run by default. However, the SQL scripts that are run in the client's env, also create the indices.

So, I have manually run the SQL command to create the index, and I got the same behavior as in the large customer application. With trunk, the test was successful(with no error message), but with 9753a, I wasn't getting either a failure nor success.

IMHO, I don't see why such a test would be successful, so the changes in 9753a actually get us closer to the OE behaviour. The next step would be to check this test with a newer OE version and take a decision based on that.

#19 Updated by Eduard Soltan about 1 year ago

  • Related to Bug #4602: fixes for OO 4GL and structured error handling added

Also available in: Atom PDF