Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A SOAP based COM+ component Stress Tool

0.00/5 (No votes)
30 Jul 2002 2  
This tool parses a SOAP request and calls the COM+ component to stress test it.

Introduction

COM+ is there for developing scalable applications. You have finished your component, and you have put it into COM+. Now you want to know how scalable is your component? The question arises, how to measure the scalability of your COM+ application? Basically there two major metrics to measure a COM+ application�s scalability: The latency and the throughput under different user load.

Latency is often called response time. From a client's perspective, it is the delay experienced between the point when a request is made and the server's response at the client is received. It is usually measured in units of time, such as seconds. In certain testing tools, such as the Microsoft� Web Application Stress (WAS) tool, latency is best represented by the metric "time to last byte" (TTLB), which calculates the time between sending out a Web page request and receiving the last byte of the complete page content.

Below is a typical latency versus user load curve.

Figure 1. Typical characteristics of latency versus user load

Throughput is another one of the most useful metrics to measure a distributed application�s scalability. It is the number of client requests the application can process within a certain unit of time. Typically, the unit of measurement is requests per second. It can help to identify performance bottlenecks and improving application and system performance. Figure 2 demonstrates typical characteristics of throughput versus user load.

Figure 2. Typical characteristics of throughput versus user load

Given the metrics, how can we know them of our COM+ application? The answer is to stress test it. But how? Microsoft and other vendors provide testing tools such as Web Application Stress (WAS) tool, but they are mainly focused on the Web application stress testing. They send http request to the web application to test it, and basically interact with the Presentation layer of the distributed application. Unfortunately it is usually too late when the presentation layer is finished and if we found the metrics don�t meet our design goal. We need to test the Data Layer and the Business Logical Layer before testing the web application as a whole to ensure bad performance is not propagated into the next layer.

That's why this stress testing tool comes into play. It is mainly focused on the Data Layer and Business Layer stress testing. It can be used in at least two scenarios. The first is to stress test Data Layer and business Layer after they are finished to make sure that they meet the design goal. The other is to trouble shoot the Data Layer and Business Layer if other stress testing tools such WAS found that the Web application's scalability is not so good.

Techniques used in this tool

One of the design goal is to make this tool suitable for all the Components that support IDispatch. To make this tool powerful, flexible yet easy to use, I make it based on the SOAP protocol. SOAP protocol is ideal for describing method calls to the component. It uses a rich type system which includes most of the types that you may use in your programming language. Yet it is easy to use and parse. As for a SOAP request, it can specify which component it is for, which method it is calling, and what are the types and values of the input parameters. I use the component's ProgID as the URI of the namespace for the request message. For example the SOAP request below is to call a component with ProgID PooledObjTest.IpooledObjTest. It is calling the component�s GetDataset method, passing a SQL query string to the parameter strSQL.

  <?xml version="1.0" standalone="yes" ?> 
- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
                     xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
                     xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
                     SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
- <SOAP-ENV:Body>
- <m:GetDataset xmlns:m="PooledObjTest.IPooledObjTest">
  <strSQL xsi:type="xsd:string">select * from orders</strSQL> 
  </m:GetDataset>
  </SOAP-ENV:Body>
  </SOAP-ENV:Envelope> 

For more information about the SOAP protocol, you can have a look at the SOAP : http://www.w3.org/TR/SOAP/

To parse the SOAP request, which is a XML file, I use the MSXML library to read the XMLDOM object tree. There are couple of important interfaces in the library such as IXMLDOMDocument and IXMLDOMNode. The IXMLDOMDocument interface represent a XML document. And the IXMLDOMNode interface represents a node in the tree. The code snippet below parse a IXMLDOMNode to yield out a Method call.

void CSoapRequestParser::ParseACall(IXMLDOMNodePtr pChild)
{
    GetNodeInfo(pChild);
    CSoapRequestCall cSoapMethod;
    CSoapRequestCall cPreSoapMethod;

    int nStartIdx = m_strName.Find(':');
    if(nStartIdx != -1)
        cSoapMethod.SetMethodName(m_strName.Right(m_strName.GetLength() 
                                       - nStartIdx - 1));
    else
        cSoapMethod.SetMethodName(m_strName);
    
    //if there is no attributes

    if(m_AttribNames.GetSize()== 0)
    {
        cPreSoapMethod = m_cSoapReq.GetMethodCall(m_cSoapReq.GetMethodCount() -1);
        cSoapMethod.SetProgID(cPreSoapMethod.GetProgID());
    }
    else
    {        
        //find the progid in the attributes;

        for(int i = 0; i< m_AttribNames.GetSize(); i++)
        {
            nStartIdx = m_AttribNames[i].Find("xmlns");
            if(nStartIdx != -1)
            {
                CString strTemp = m_AttribValues[i];
                strTemp.TrimLeft();
                strTemp.TrimRight();
                cSoapMethod.SetProgID(strTemp);
                break;
            }
            else
            {
                //if we omit the prog id, we set it to the same as the prevous one.

                cPreSoapMethod = m_cSoapReq.GetMethodCall(m_cSoapReq.GetMethodCount() -1);
                cSoapMethod.SetProgID(cPreSoapMethod.GetProgID());
            }
        }    
    }
    
    //parse the parameters.

    ParseParams(pChild, cSoapMethod);

    m_cSoapReq.AddMethodCall(cSoapMethod);
}

After the SOAP request file is parsed, we need to create and call the component. To achieve the flexibility of calling different components based on the ProgID, I use late binding. To call IDispatch directly from VC++ is not so easy in my opinion. The most tedious task is to package the parameters into a DISPPARAMS parameter. Thanks to Xiangyang Liu�s cool article Getting the most out of IDispatch, it make the task much easier. It uses ITypeInfo interface to read the type library of the component and generate the necessary information to call the IDispatch interface. I modified the code to load the type library information from Xiangyang Liu's article.

To simulate multiple connections at the same time, I use the multiple-threads to create the COM+ component and to call its methods. To display the result, I use the MsChart control, which is ideal for displaying charts. The code below calls the MsChart control to display the Request Per Second (RPS) result.

void CTestClientDlg::UpdateChartRPS(int nFinished)
{
    COleSafeArray saRet;
    
    DWORD numElements[] = {TESTROUNDS, 2}; // 10x10

    
    // Create the safe-array...    

    saRet.Create(VT_VARIANT, 2, numElements);
    
    // Initialize it with values...    

    long index[2];
    
    for(index[0]=0; index[0]< TESTROUNDS; index[0]++) {
        for(index[1]=0; index[1]<2; index[1]++) {
            if(index[1] == 0)
            {
                VARIANT v;
                CString str;
                str.Format("%u Threads", m_uThreadNum[index[0]]);

                v.vt = VT_BSTR;
                v.bstrVal = _bstr_t(str);
                saRet.PutElement(index, &v);
            }
            else
            {
                VARIANT v;
                v.vt = VT_I4;
                if(index[0] <= nFinished)
                    v.lVal = m_dwRPSResult[index[0]];
                else
                    v.lVal = 0;
                saRet.PutElement(index, &v);
            }
        }
    }
    
    // Return the safe-array encapsulated in a VARIANT...    

    m_ctlChart.SetChartData(saRet.Detach());    
    m_ctlChart.Refresh();              
    
    UpdateWindow();

}

How to use this tool

To use this SOAP based COM+ component stress tool, you need to:

  1. Create a XML file to describe what component and what methods you want to call in a round of test. You can do it with any XML editor, or you can use the Notepad if you like. You can start with the sample SOAP request described in the previous section, but be sure to change the xmlns:m namespace to the ProgID of your component, and change the GetDataSet node name to the name of the method. Also be sure to change the strSQL to the name of the parameter. You can check the component�s parameter names with the OLEView tool. Next you need to change "xsd:string" to the type of your parameter. Finally you need to change to the text of the strSQL node to the appropriate parameter value.

    Though there is only one method call in the sample SOAP request, you can add more method calls to it to make it like a typical client session.

    NOTE: All the names in the SOAP request file is case-sensitive.

  2. Start TestClient.exe and click on the Open File button. Select the XML file you have created in step 1 and click Open button.

    Figure3. Open the XML file.

  3. Specify the Thread numbers in the textbox controls. Or you can use the default thread numbers. The TestClient will start the number of threads at the same time to call the COM+ component�s methods simultaneously.

  4. Click on the Latency Test, or the Throughput test button to start test. It will report the testing result with the MsChart control.

Sample Test Results

Figure 4. A sample Latency test result .

Figure 5. A sample Throughput test result .

Known Limitations and issues

There are a couple of the known limitations and issues about this SOAP based stress testing tool. First of all, since it uses IDispatch to invoke the methods of the component, it requires that your component to support IDispatch. Next, for the time being it doesn�t support all the parameter types that the SOAP supports. For example it doesn�t supports arrays and structures. Finally it reports the result on the screen and doesn�t save the result on the disk. You can extend it to add that feature.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here