X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=csit%2Flibraries%2FWaitUtils.robot;h=7968ead0219c5acdcf4f021709d0cae207efc85a;hb=8e9254858354ce7632f9d7f104aea82c6cc0630b;hp=15787e91e49fbfec606c97dc98eb7e649a806fe3;hpb=8252a1e83666ddb607256e77550c2f9d535191a7;p=integration%2Ftest.git diff --git a/csit/libraries/WaitUtils.robot b/csit/libraries/WaitUtils.robot index 15787e91e4..7968ead021 100644 --- a/csit/libraries/WaitUtils.robot +++ b/csit/libraries/WaitUtils.robot @@ -8,10 +8,11 @@ Documentation Robot keyword library (Resource) with several Keywords for mon ... and is available at http://www.eclipse.org/legal/epl-v10.html ... ... -... BuiltIn.Wait_Until_Keyword_Succeeds is useful in avoiding unnecessary sleeps. -... But several usage cases need slightly different logic, here are Keywords for that. +... BuiltIn.Wait_Until_Keyword_Succeeds has two possible results: Fast pass or fail on timeout. +... Generally, keywords in this Resource also allow for some kind of fast failure condition. +... This usually requires more than a single keyword to run inside the iteration loop. +... This library uses ScalarClosures for plugging in specific (multiple) Keywords. ... -... This library uses ScalarClosures for plugging in specific Keywords. ... Storing private state in suite variables is easy, but it can lead to hard-to-debug issues, ... so this library tries to support explicit state passing. ... Unfortunately, failing limits type of message to return, @@ -26,7 +27,7 @@ Documentation Robot keyword library (Resource) with several Keywords for mon ... Safe Stateful Validator: Take ${state} and ${data} arguments. Return new state, validation status and comment/message. ... TODO: Create a dummy closure for each type to be used as default value? ... -... TODO: Figure out a way to merge this with FaitForFailure.robot +... TODO: Figure out a way to merge this with WaitForFailure.robot ... TODO: Add Keywords that are Safe (return state, success and message) ... so that callers do not need to refresh state explicitly. Library DateTime @@ -85,28 +86,46 @@ WaitUtils__Is_Deadline_Reachable ${time_minimal} = BuiltIn.Evaluate int(${sleeps_left}) * ${period_in_seconds} BuiltIn.Run_Keyword_If ${time_minimal} >= ${time_deadline} BuiltIn.Fail Not possible to succeed within the deadline. ${message} +Wait_For_Getter_Failure_Or_Stateless_Validator_Pass + [Arguments] ${timeout}=60s ${period}=1s ${getter}=${ScalarClosures__fail} ${stateless_validator}=${ScalarClosures__identity} + [Documentation] Repeatedly run getter and plug its output to validator. If both pass, return validator message. + ... If getter fails, fail. If validator fails, repeat in WUKS fashion (fail when timeout is exceeded). + ... FIXME: Cover this keyword in WaitUtilTest.robot + ${timeout_in_seconds} ${period_in_seconds} ${date_deadline} = WaitUtils__Check_Sanity_And_Compute_Derived_Times timeout=${timeout} period=${period} + ${iterations} = BuiltIn.Evaluate ${timeout_in_seconds} / ${period_in_seconds} + FOR ${i} IN RANGE ${iterations} + ${data} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_As_Is ${getter} + ${status} ${message} = BuiltIn.Run_Keyword_And_Ignore_Error ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_After_Replacing_First_Argument ${stateless_validator} + ... ${data} + BuiltIn.Return_From_Keyword_If "${status}" == "PASS" ${message} + WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} message=Last validator message: ${message} + BuiltIn.Sleep ${period_in_seconds} s + END + BuiltIn.Fail Logic error, we should have returned before. + Stateless_Assert_Closure_Has_To_Succeed_Consecutively_By_Deadline [Arguments] ${date_deadline}=0 ${period_in_seconds}=1 ${count}=1 ${assertor}=${ScalarClosures__fail} - [Documentation] Pass only if ${assertor} passes ${count} times in a row with ${period_in_seconds} between attempts; less standard arguments. + [Documentation] Pass only if \${assertor} passes ${count} times in a row with ${period_in_seconds} between attempts; less standard arguments. ${result} = BuiltIn.Set_Variable No result yet. # Do we have enough time to succeed? ${sleeps} = BuiltIn.Evaluate ${count} - 1 WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} sleeps_left=${sleeps} message=Last result: ${result} # Entering the main loop. - : FOR ${sleeps_left} IN RANGE ${count}-1 -1 -1 # If count is 3, for will go through 2, 1, and 0. - \ # Run the assertor and collect the garbage. - \ ${result} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_As_Is ${assertor} - \ # We have not failed yet. Was this the final try? - \ BuiltIn.Return_From_Keyword_If ${sleeps_left} <= 0 ${result} - \ # Is there enough time left? - \ WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} sleeps_left=${sleeps_left} message=Last result: ${result} - \ # We will do next try, byt we have to sleep before. - \ BuiltIn.Sleep ${period_in_seconds} s + FOR ${sleeps_left} IN RANGE ${count}-1 -1 -1 # If count is 3, for will go through 2, 1, and 0. + # Run the assertor and collect the garbage. + ${result} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_As_Is ${assertor} + # We have not failed yet. Was this the final try? + BuiltIn.Return_From_Keyword_If ${sleeps_left} <= 0 ${result} + # Is there enough time left? + WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} sleeps_left=${sleeps_left} message=Last result: ${result} + # We will do next try, byt we have to sleep before. + BuiltIn.Sleep ${period_in_seconds} s + END BuiltIn.Fail Logic error, we should have returned before. Stateless_Assert_Closure_Has_To_Succeed_Consecutively [Arguments] ${timeout}=60s ${period}=1s ${count}=1 ${assertor}=${ScalarClosures__fail} - [Documentation] Pass only if ${assertor} passes ${count} times in a row with ${period} between attempts; standard arguments. + [Documentation] Pass only if \${assertor} passes ${count} times in a row with ${period} between attempts; standard arguments. # TODO: Put default values into variables for users to override at pybot invocation? ${timeout_in_seconds} ${period_in_seconds} ${date_deadline} = WaitUtils__Check_Sanity_And_Compute_Derived_Times timeout=${timeout} period=${period} count=${count} ${result} = Stateless_Assert_Closure_Has_To_Succeed_Consecutively_By_Deadline date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} count=${count} assertor=${assertor} @@ -114,7 +133,7 @@ Stateless_Assert_Closure_Has_To_Succeed_Consecutively Stateful_Assert_Closure_Has_To_Succeed_Consecutively_By_Deadline [Arguments] ${date_deadline}=0 ${period_in_seconds}=1 ${count}=1 ${assertor}=${ScalarClosures__fail} ${initial_state}=${None} - [Documentation] Pass only if ${assertor} passes ${count} times in a row with ${period} between attempts. Keep assertor state in local variable. Less standard arguments. + [Documentation] Pass only if $\{assertor} passes ${count} times in a row with ${period} between attempts. Keep assertor state in local variable. Less standard arguments. # TODO: Put default values into variables for users to override. ${result} = BuiltIn.Set_Variable No result yet. ${state} = BuiltIn.Set_Variable ${initial_state} @@ -122,19 +141,20 @@ Stateful_Assert_Closure_Has_To_Succeed_Consecutively_By_Deadline ${sleeps} = BuiltIn.Evaluate ${count} - 1 WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} sleeps_left=${sleeps} message=Last result: ${result} # Entering the main loop. - : FOR ${sleeps_left} IN RANGE ${count}-1 -1 -1 - \ ${state} ${result} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_After_Replacing_First_Argument ${assertor} ${state} - \ # We have not failed yet. Was this the final try? - \ BuiltIn.Return_From_Keyword_If ${sleeps_left} <= 0 ${result} - \ # Is there enough time left? - \ WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} sleeps_left=${sleeps_left} message=Last result: ${result} - \ # We will do next try, byt we have to sleep before. - \ BuiltIn.Sleep ${period_in_seconds} s + FOR ${sleeps_left} IN RANGE ${count}-1 -1 -1 + ${state} ${result} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_After_Replacing_First_Argument ${assertor} ${state} + # We have not failed yet. Was this the final try? + BuiltIn.Return_From_Keyword_If ${sleeps_left} <= 0 ${result} + # Is there enough time left? + WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} sleeps_left=${sleeps_left} message=Last result: ${result} + # We will do next try, byt we have to sleep before. + BuiltIn.Sleep ${period_in_seconds} s + END BuiltIn.Fail Logic error, we should have returned before. Stateful_Assert_Closure_Has_To_Succeed_Consecutively [Arguments] ${timeout}=60s ${period}=1s ${count}=1 ${assertor}=${ScalarClosures__fail} ${initial_state}=${NONE} - [Documentation] Pass only if ${assertor} passes ${count} times in a row with ${period} between attempts. Keep assertor state in local variable. Standard arguments. + [Documentation] Pass only if \${assertor} passes ${count} times in a row with ${period} between attempts. Keep assertor state in local variable. Standard arguments. # TODO: Put default values into variables for users to override. ${timeout_in_seconds} ${period_in_seconds} ${date_deadline} = WaitUtils__Check_Sanity_And_Compute_Derived_Times timeout=${timeout} period=${period} count=${count} ${result} = Stateful_Assert_Closure_Has_To_Succeed_Consecutively_By_Deadline date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} count=${count} assertor=${assertor} initial_state=${initial_state} @@ -142,7 +162,7 @@ Stateful_Assert_Closure_Has_To_Succeed_Consecutively Getter_And_Safe_Stateful_Validator_Have_To_Succeed_Consecutively_By_Deadline [Arguments] ${date_deadline}=0 ${period_in_seconds}=1 ${count}=1 ${getter}=${ScalarClosures__fail} ${safe_validator}=${ScalarClosures__fail} ${initial_state}=${NONE} - [Documentation] Pass only if consecutively ${count} times in a row with ${period} between attempts: ${getter} creates data and ${safe_validator} passes. Validator updates its state even if it reports failure. Always return validator state, status and message. + [Documentation] Pass only if consecutively ${count} times in a row with ${period} between attempts: \${getter} creates data and \${safe_validator} passes. Validator updates its state even if it reports failure. Always return validator state, status and message. ${result} = BuiltIn.Set_Variable No result yet. ${state} = BuiltIn.Set_Variable ${initial_state} # Do we have enough time to succeed? @@ -151,26 +171,27 @@ Getter_And_Safe_Stateful_Validator_Have_To_Succeed_Consecutively_By_Deadline ... message=Last result: ${result} BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} ${message} # Entering the main loop. - : FOR ${sleeps_left} IN RANGE ${count}-1 -1 -1 - \ # Getter may fail, but this Keyword should return state, so we need RKAIE. - \ ${status} ${data} = BuiltIn.Run_Keyword_And_Ignore_Error ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_As_Is ${getter} - \ BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} Getter failed: ${data} - \ # Is there enough time left? - \ ${status} ${message} = BuiltIn.Run_Keyword_And_Ignore_Error WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} - \ ... sleeps_left=${sleeps_left} message=Last result: ${result} - \ BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} ${message} - \ ${state} ${status} ${result} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_After_Replacing_First_Two_Arguments ${safe_validator} - \ ... ${state} ${data} - \ # Validator may have reported failure. - \ BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} Validator failed: ${result} - \ # Was this the final try? - \ BuiltIn.Return_From_Keyword_If ${sleeps_left} <= 0 ${state} ${status} ${result} - \ # Is there enough time left? - \ ${status} ${message} = BuiltIn.Run_Keyword_And_Ignore_Error WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} - \ ... sleeps_left=${sleeps_left} message=Last result: ${result} - \ BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} ${message} - \ # We will do next try, byt we have to sleep before. - \ BuiltIn.Sleep ${period_in_seconds} s + FOR ${sleeps_left} IN RANGE ${count}-1 -1 -1 + # Getter may fail, but this Keyword should return state, so we need RKAIE. + ${status} ${data} = BuiltIn.Run_Keyword_And_Ignore_Error ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_As_Is ${getter} + BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} Getter failed: ${data} + # Is there enough time left? + ${status} ${message} = BuiltIn.Run_Keyword_And_Ignore_Error WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} + ... sleeps_left=${sleeps_left} message=Last result: ${result} + BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} ${message} + ${state} ${status} ${result} = ScalarClosures.Run_Keyword_And_Collect_Garbage ScalarClosures.Run_Closure_After_Replacing_First_Two_Arguments ${safe_validator} + ... ${state} ${data} + # Validator may have reported failure. + BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} Validator failed: ${result} + # Was this the final try? + BuiltIn.Return_From_Keyword_If ${sleeps_left} <= 0 ${state} ${status} ${result} + # Is there enough time left? + ${status} ${message} = BuiltIn.Run_Keyword_And_Ignore_Error WaitUtils__Is_Deadline_Reachable date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} + ... sleeps_left=${sleeps_left} message=Last result: ${result} + BuiltIn.Return_From_Keyword_If '''${status}''' != '''PASS''' ${state} ${status} ${message} + # We will do next try, byt we have to sleep before. + BuiltIn.Sleep ${period_in_seconds} s + END BuiltIn.Fail Logic error, we should have returned before. Propagate_Fail_If_Message_Starts_With_Prefix @@ -193,40 +214,45 @@ Wait_For_Getter_And_Safe_Stateful_Validator_Consecutive_Success [Documentation] Analogue of Wait Until Keyword Succeeds, but it passes state of validator around. Calls GASSVHTSCBD to verify data is "stable". # FIXME: Document that Safe Stateful Validator has to return state, status and message (and never fail) ${timeout_in_seconds} ${period_in_seconds} ${date_deadline} = WaitUtils__Check_Sanity_And_Compute_Derived_Times timeout=${timeout} period=${period} count=${count} - # Maximum number of tries. TODO: Move to separate Keyword? - ${maximum_tries} = BuiltIn.Evaluate math.ceil(${timeout_in_seconds} / ${period_in_seconds}) modules=math + # Maximum number of sleeps. TODO: Move to separate Keyword? + ${maximum_sleeps} = BuiltIn.Evaluate math.ceil(${timeout_in_seconds} / ${period_in_seconds}) + 1 modules=math ${result} = BuiltIn.Set_Variable No result yet. ${state} = BuiltIn.Set_Variable ${initial_state} # The loop for failures. - : FOR ${try} IN RANGE 1 ${maximum_tries} - \ ${state} ${status} ${result} = Getter_And_Safe_Stateful_Validator_Have_To_Succeed_Consecutively_By_Deadline date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} - \ ... count=${count} getter=${getter} safe_validator=${safe_validator} initial_state=${state} - \ # Have we passed? - \ BuiltIn.Return_From_Keyword_If '''${status}''' == '''PASS''' ${result} - \ # Are we out of time? - \ Propagate_Fail_If_Message_Starts_With_Prefix ${result} Not possible to succeed within the deadline. - \ # We will do next try, but we have to sleep before. - \ BuiltIn.Sleep ${period_in_seconds} s + FOR ${try} IN RANGE 1 ${maximum_sleeps}+2 # If maximum_sleeps is 2, for will go through 1, 2, and 3. + ${state} ${status} ${result} = Getter_And_Safe_Stateful_Validator_Have_To_Succeed_Consecutively_By_Deadline date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} + ... count=${count} getter=${getter} safe_validator=${safe_validator} initial_state=${state} + # Have we passed? + BuiltIn.Return_From_Keyword_If '''${status}''' == '''PASS''' ${result} + # Are we out of time? + Propagate_Fail_If_Message_Starts_With_Prefix ${result} Not possible to succeed within the deadline. + # We will do next try, but we have to sleep before. + BuiltIn.Sleep ${period_in_seconds} s + END BuiltIn.Fail Logic error, we should have returned before. Wait_For_Getter_Error_Or_Safe_Stateful_Validator_Consecutive_Success [Arguments] ${timeout}=60s ${period}=1s ${count}=1 ${getter}=${ScalarClosures__fail} ${safe_validator}=${ScalarClosures__fail} ${initial_state}=${NONE} [Documentation] Analogue of Wait Until Keyword Succeeds, but it passes state of validator around and exits early on getter failure. Calls GASSVHTSCBD to verify data is "stable". + # If this ever fails, we want to know the exact inputs passed to it. + ${tmp}= BuiltIn.Evaluate int(${count}) + BuiltIn.Log count=${tmp} ${timeout_in_seconds} ${period_in_seconds} ${date_deadline} = WaitUtils__Check_Sanity_And_Compute_Derived_Times timeout=${timeout} period=${period} count=${count} - # Maximum number of tries. TODO: Move to separate Keyword or add into CSACDT? - ${maximum_tries} = BuiltIn.Evaluate math.ceil(${timeout_in_seconds} / ${period_in_seconds}) modules=math + # Maximum number of sleeps. TODO: Move to separate Keyword or add into CSACDT? + ${maximum_sleeps} = BuiltIn.Evaluate math.ceil(${timeout_in_seconds} / ${period_in_seconds}) modules=math ${result} = BuiltIn.Set_Variable No result yet. ${state} = BuiltIn.Set_Variable ${initial_state} # The loop for failures. - : FOR ${try} IN RANGE 1 ${maximum_tries} - \ ${state} ${status} ${result} = Getter_And_Safe_Stateful_Validator_Have_To_Succeed_Consecutively_By_Deadline date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} - \ ... count=${count} getter=${getter} safe_validator=${safe_validator} initial_state=${state} - \ # Have we passed? - \ BuiltIn.Return_From_Keyword_If '''${status}''' == '''PASS''' ${result} - \ # Are we out of time? Look at ${result}. - \ Propagate_Fail_If_Message_Starts_With_Prefix ${result} Not possible to succeed within the deadline. - \ # Now check for getter error, by analysing ${result}. - \ Propagate_Fail_If_Message_Starts_With_Prefix ${result} Getter failed - \ # We can do the next try, byt we have to sleep before. - \ BuiltIn.Sleep ${period_in_seconds} s + FOR ${try} IN RANGE 1 ${maximum_sleeps}+2 # If maximum_sleeps is 2, for will go through 1, 2, and 3. + ${state} ${status} ${result} = Getter_And_Safe_Stateful_Validator_Have_To_Succeed_Consecutively_By_Deadline date_deadline=${date_deadline} period_in_seconds=${period_in_seconds} + ... count=${count} getter=${getter} safe_validator=${safe_validator} initial_state=${state} + # Have we passed? + BuiltIn.Return_From_Keyword_If '''${status}''' == '''PASS''' ${result} + # Are we out of time? Look at ${result}. + Propagate_Fail_If_Message_Starts_With_Prefix ${result} Not possible to succeed within the deadline. + # Now check for getter error, by analysing ${result}. + Propagate_Fail_If_Message_Starts_With_Prefix ${result} Getter failed + # We can do the next try, byt we have to sleep before. + BuiltIn.Sleep ${period_in_seconds} s + END BuiltIn.Fail Logic error, we should have returned before.