Forum Discussion

Stalsy's avatar
Stalsy
Contributor
3 years ago
Solved

Authorisation token expires too soon

 I'm running data-driven tests that have 5 steps:

  1. 1. Get new Authorisation token
  2. 2. DataSource (get a few thousand random rows from DB2)
  3. 3. REST Request 
  4. 4. Assert script 
  5. 5. DataSource Loop

The problem is that the Authorisation token expires after say 30 seconds, so if I increase the number of rows in my select statement, after 30 seconds every REST request fails with 401 - unauthorized.

I set in Auth Repository the 'Access Token Expiration Time'  of my OAuth 2.0 (Azure) profile to Custom/25 Seconds but nothing changed.

I could not find anything on static variables so I implemented the following:

//test case property "Duration" to simulate static variable

//get value of property "Duration"

def dur = testRunner.testCase.getPropertyValue("Duration").toInteger() 

//if test is more than 'Duration' get another token and increment 'Duration'

if ( testRunner.getTimeTaken() > dur)
{
testRunner.gotoStepByName('GetAcessToken')
testRunner.testCase.setPropertyValue( "Duration", (dur+30000).toString() )
dur = testRunner.testCase.getPropertyValue("Duration").toInteger()
}

This solution has 2 issues:

  1. 1. For every test I need an extra Initialisation step to reset the Duration property to  (testRunner.testCase.setPropertyValue( 'Duration', '30000' ) for the next run
  2. 2. After running the Get Access token step, ReadyAPI continues on with a new Data Source step so the test will never end!

The only way I see how to resolve this is instead of  asking ReadyAPI to run step GetAcessToken:

testRunner.gotoStepByName('GetAcessToken')

is to replace this line of code with all the code of  step GetAcessToken.

Surely there must be a more elegant solution

 

  • Stalsy's avatar
    Stalsy
    3 years ago

    The acquisition of a new access token is very slow so I can't afford to have it inside the loop. As you can see from the code snippet below I request for a new token and then wait in a loop till I have one:

    def oldToken = oAuthProfile.getAccessToken();

    def oAuthClientFacade = new OltuOAuth2AzureClientFacade (TokenType.ACCESS);
    oAuthClientFacade.requestAccessToken(oAuthProfile, true,true);

    while(oldToken == oAuthProfile.getAccessToken())

    {
      sleep(100);
    }

     

    I'm pretty happy with what I've got now:

    I get the access token in the TestRunListener.beforeRun event which also sets a test case property "Duration" to the time I want to wait till I need another token.

    Inside the test loop, in my groovy asserts script, I check if the test has been running for a time exceeding the Duration property, and if yes, I get a new access token and increment the Duration property

6 Replies

  • TNeuschwanger's avatar
    TNeuschwanger
    Champion Level 2

    You have 5 steps listed in your original question...  Why not switch positions between 1 and 2?  You get a new token each loop before the REST step is invoked.  Is there a price to pay for generating a Token? If not, why not just regenerate the token inside the loop.

    • Stalsy's avatar
      Stalsy
      Contributor

      The acquisition of a new access token is very slow so I can't afford to have it inside the loop. As you can see from the code snippet below I request for a new token and then wait in a loop till I have one:

      def oldToken = oAuthProfile.getAccessToken();

      def oAuthClientFacade = new OltuOAuth2AzureClientFacade (TokenType.ACCESS);
      oAuthClientFacade.requestAccessToken(oAuthProfile, true,true);

      while(oldToken == oAuthProfile.getAccessToken())

      {
        sleep(100);
      }

       

      I'm pretty happy with what I've got now:

      I get the access token in the TestRunListener.beforeRun event which also sets a test case property "Duration" to the time I want to wait till I need another token.

      Inside the test loop, in my groovy asserts script, I check if the test has been running for a time exceeding the Duration property, and if yes, I get a new access token and increment the Duration property

  • nmrao's avatar
    nmrao
    Champion Level 3
    May be you want to check with your team regarding increasing the expiration time.
    • Stalsy's avatar
      Stalsy
      Contributor
      The expiration time is actually 1 hour! I said 30 seconds as an example. Some of the data is very old and I'm trying to do 100% coverage. There are about 150K rows and I've been testing 1-4k random rows per time, but when the errors are all "discovered", I want to do all 150k rows. What I've done works, I've set the Duration property to 30000000ms and run it for 40,000 rows. After about 20,000 requests I saw the property go to 60000000 and then I interrupted the test. My problem is that it's very clumsy and verbose and I need to do it for every test case. I tried using events, using a static method in my script library but no luck.
  • My "final Solution":

    I implemented event TestRunListener.beforeRun which runs before each test.  Here I get a new access token and initialize the Duration property to a few minutes less than the life of the token.

    My tests have a Datasource step, the Rest request, the Assert step and finally the Data Source loop step.

    In the Assert step, if testRunenr.getTimeTaken() > Duration (i.e. my test has been running for a time  approaching  the token expiration), I get a new token and increment the value of the Duration property by another chuck of minutes equal to a few minutes less than the life of the token. 

     

    I tried in vain to implement the acquiring of the new token as a script library method (getNewAccessToken(project)) so that I don't have to copy/paste the same code in every Assert test-step, but ReadyApi says I have a compilation error and I don't know how to debug ReadyAPI groovy library  scripts.  I have other script library methods that work fine... furthermore, the code in the method is almost identical to the code in the TestRunListener.beforeRun event except that I'm passing the project as a parameter... Still, it does not work and I have no way of debugging it!