navigation
 Thursday, February 21, 2008

I was designing a load test against Active Focus the other day using TestComplete. I kept getting the error "Connection 0 of the task assigned to the virtual user VirtualUser1 was simulated partially. Only 3 of 41 requests were completed." in the test log.  The problem was that viewstate being sent (the record one), did not match the expect viewstate at the web server (probably something to do with security). So to fix this problem, I needed to capture the viewstate from the previous HTTP response and place it in the HTTP request.

[VBScript]

Dim ViewState

Sub ProjectEvents1_OnLoadTestingResponse(Sender, User, Request)
   ViewState = ExtractViewState(Request.ResponseBody.Contents)
End Sub

Function ExtractViewState(HTMLPage)
   Dim RegEx
   Set RegEx = New RegExp
   RegEx.IgnoreCase = True
   RegEx.Pattern = "__viewstate[^>]+value=\""([^\""]*)"
   Set Matches = RegEx.Execute(HTMLPage)
   if Matches.Count > 0 Then
     ExtractViewState = Matches(0).SubMatches(0)
   Else
      ExtractViewState = ""
   End If
End Function

Sub ProjectEvents1_OnLoadTestingRequest(Sender, User, Request)
   Request.Variables.Item("__VIEWSTATE") = ViewState
End Sub

Sub SetResponseEventTriggerForAllRequests(Task)
   TaskConnectionCount = Task.ConnectionCount
   for i = 0 to TaskConnectionCount - 1
       ConnectionRequestCount = Task.Connection(i).RequestCount
       for j = 0 to ConnectionRequestCount - 1
           Task.Connection(i).Request(j).ResponseEventTrigger = True
       Next
   Next
End Sub

Sub SetRequestEventTriggerForAllRequests(Task)
   TaskConnectionCount = Task.ConnectionCount
   for i = 0 to TaskConnectionCount - 1
       ConnectionRequestCount = Task.Connection(i).RequestCount
       for j = 0 to ConnectionRequestCount - 1
           Task.Connection(i).Request(j).RequestEventTrigger = True
       Next
   Next
End Sub

Sub TestViewState
   Set HTTPTask = LoadTesting.HTTPTask("ViewStateTask")
   Set VirtualUser = LoadTesting.CreateVirtualUser("VirtualUser1")
   Set VirtualUser.Task = HTTPTask
   SetResponseEventTriggerForAllRequests(VirtualUser.Task)
   SetRequestEventTriggerForAllRequests(VirtualUser.Task)

   ' Sets the initial value for the ViewState variable
   ViewState = ""

   Call VirtualUser.Run("ViewState")
End Sub
Now this code works fine for one virtual user, but that is not much of a load test :).
Depend on the task assigned to the virtual user, the viewstate can be different from user to user.
The follow changes will allow you to set the load test to any number of users.
[VBScript]
Sub TestViewState
  Dim TaskVar, TestInstance, i, UserVar(5)
  Set TaskVar = LoadTesting.HTTPTask("ViewStateTask2")
  SetResponseEventTriggerForAllRequests(VirtualUser.Task)
  SetRequestEventTriggerForAllRequests(VirtualUser.Task)
  Set TestInstance = LoadTesting.CreateTestInstance("TestInstanceName")
  For i = 0 To 4
    Set UserVar(i) = LoadTesting.CreateVirtualUser("VirtualUserName_" + VarToStr(i))
    Set UserVar(i).Task = TaskVar 
    Set UserVar(i).TestInstance = TestInstance 
  Next
  Set ViewState = Sys.OleObject("scripting.dictionary")
  TestInstance.Run "ViewState" 
End Sub 

Sub GeneralEvents_OnLoadTestingRequest(Sender, User, Request)
  Request.Variables.Item("__VIEWSTATE") = ViewState(User.Name)
End Sub 

Sub GeneralEvents_OnLoadTestingResponse(Sender, User, Request)
   If ViewState.Exists(User.Name) Then
     ViewState.Remove(User.Name)
   end if
   Call ViewState.add(User.Name,ExtractViewState(Request.ResponseBody.Contents))
End Sub 

NOTE: The ExtractViewState Function will only work if HTTP compression is turned off.