Enabling MBS Performance Testing with LoadRunner

Use the sample test program to perform load testing of MBS in Sybase Unwired Platform with LoadRunner.

  1. Create an empty .NET script in LoadRunner and edit it in Microsoft Visual Studio.
  2. In LoadRunner 11, set the target platform to .NET Framework 3.5.
  3. Include the MBS OAPI code that you generated. To generate MBS code from the command line:
    codegen -output <outputDir> -mbs -cs -client -domain testdomain -sqlite <deployment_unit.xml> 
  4. Reference the following libraries:
    • sup-client.dll
    • System.Data.SQLite.dll
    • System.Data (.NET)
    • System

    The following is the example code for vuser_init.cs. USER_IDENTIFIER = "Client-2" assigns a constant value to allow the program to run in Visual Studio. Although different VUs have their own directory and database file, because the connection profile is shared you must avoid calling ConnectionProfile.save().

    vuser_init.cs 
    //---------------------------------------------
    //Script Title        :
    //Script Description  :
    //
    //
    //Recorder Version    :
    //---------------------------------------------
    using System;
    using System.IO;
    	
    using Sybase.UnwiredPlatform;
    using Sybase.UnwiredPlatform.Data;
    using Sybase.Mobile.Framework;
    using Sybase.Mobile;
    using Sybase.MessagingClientLib;
    using Sybase.Persistence;
    using Sybase.Reflection;
    using Sample;
    using LoadRunner;
    	
    namespace Script
    {
      public partial class VuserClass
      {
        // Connection Information for SAP Mobile Server
        private const String USERNAME = "supAdmin";
        private const String PASSWORD = "s3pAdmin";
        private const String HOST = "10.172.85.200"; //"PALN00527192A";
        private const int PORT = 5011; // typically 5001
    	
        // Registration timeout in seconds
        private const int TIMEOUT = 60;
    	
        // The Messaging Client Application
        private Sybase.Mobile.Application app;
    	
        private String USER_IDENTIFIER;
        private String USER_DATA_DIRECTORY;
    	
    	
        public int vuser_init()
        {
          // initialize this instance to identifie separate users
          USER_IDENTIFIER = "Client" + lr.vuser_id.ToString();
          //USER_IDENTIFIER = "Client-2";
          USER_DATA_DIRECTORY = Directory.GetCurrentDirectory() + "\\" + USER_IDENTIFIER;
    	
          // initialize client library
          app = Sybase.Mobile.Application.GetInstance(USER_IDENTIFIER, USER_DATA_DIRECTORY);
          app.ApplicationIdentifier = "Sample";
    	
          ConnectionProfile cp = SampleDB.GetConnectionProfile();
          cp.SetProperty("databaseFile", USER_DATA_DIRECTORY + "\\database.udb");
          //don't call cp.Save() otherwise multiple vu will contend on the same .scp file
          //cp.Save();
    	
          //Make sure databaseFile peroperty on the connection profile is setup before setApplication
          //because SetApplication will create the database
          SampleDB.SetApplication(app);
          SampleDB.GetSynchronizationProfile().ServerName = HOST;
    	
    	
          ConnectionProperties connProps = app.ConnectionProperties;
          LoginCredentials loginCredentials = new LoginCredentials(USERNAME, PASSWORD);
          connProps.LoginCredentials = loginCredentials;
          connProps.ServerName = HOST;
          connProps.PortNumber = PORT;
    	
          if (app.RegistrationStatus != RegistrationStatus.REGISTERED)
          {
            lr.start_transaction("Register Application");
            app.RegisterApplication(TIMEOUT);
            lr.end_transaction("Register Application", lr.AUTO);
          }
    	                  	            {
            app.StartConnection(TIMEOUT);
          }
          return 0;
    	
        }
      }
    }

    The following is the example code for Action.cs. The test code subscribes to the package you deployed to the server, waits for the server to push the data, and when all data are imported, continues the main thread and executes a findAll method. You can add more test code such as CUD (create, update, and delete) operations. The lr.think_time(1) call inserts think time between actions and can be configured dynamically in the runtime settings.

    //---------------------------------------------
    //Script Title        :
    //Script Description  :
    //
    //
    //Recorder Version    :
    //---------------------------------------------
    
    using Sybase.UnwiredPlatform;
    using Sybase.UnwiredPlatform.Data;
    using Sybase.Mobile.Framework;
    using Sybase.Mobile;
    using Sybase.MessagingClientLib;
    using Sybase.Persistence;
    using Sybase.Reflection;
    using LoadRunner;
    using System.Threading;
    using Sample;
    
    namespace Script
    {
      public partial class VuserClass
      {
        private static int IMPORT_TIMEOUT = 300000;
        public int Action()
        {
          Sample.SampleDB.BeginOnlineLogin();
          bool success = true;
          if (!Sample.SampleDB.IsSubscribed())
          {
            subscribe();
            lock (this)
            {
              lr.start_transaction("wait for import");
              success = Monitor.Wait(this, IMPORT_TIMEOUT);
              if (success)
              {
                lr.end_transaction("wait for import", lr.AUTO);
              }
              else
              {
                lr.end_transaction("wait for import", lr.FAIL);
              }
            }
    
              }
    
    
                if (success)
                {
                    query();
                    return 0;
                }
                else
                {
                    return 1;
                }
          }
    
          //a transaction to register and begin sync
          public int subscribe()
          {
            //can be overrided by runtime setting in controller
            lr.think_time(1);
            lr.start_transaction("subscribe Application");
            SampleDB.RegisterCallbackHandler(new PerfCallback(this));
    
            Sample.SampleDB.Subscribe();
    
            lr.end_transaction("subscribe Application", lr.AUTO);
            return 0;
          }
    
    
          public int query()
          {
            //can be overrided by runtime setting in controller
            lr.think_time(1);
            lr.start_transaction("FindAll");
            Sybase.Collections.GenericList<Customer> cusList =  Customer.FindAll();
            lr.end_transaction("FindAll", lr.AUTO);
            if (cusList.Size() > 0)
            {
              return 0;
            }
            else
            {
              return 1;
            }
          }
        }
    
        public class PerfCallback: Sybase.Persistence.DefaultCallbackHandler, ICallbackHandler
        {
          private object obj;
    
          //obj: lock object to be notified
          public PerfCallback(object obj)
          {
            this.obj = obj;
        }
    
        override public void OnImportSuccess()
        {
          lock (obj)
          {
            Monitor.Pulse(obj);
          }
        }
    
      }
    }

    The following is the example code for vuser_end.cs:

    Note: If you do not include a TIMEOUT parameter in app.UnregisterApplication(TIMEOUT);, the call is an asynchronous method and immediately returns. The next statement is DeleteDatabase; these two operations may interfere and result in an error at the server. It is possible that no further app.RegisterApplication(TIMEOUT) calls may succeed.
    //---------------------------------------------
    //Script Title        :
    //Script Description  :
    //
    //
    //Recorder Version    :
    //---------------------------------------------
    
    using Sample;
    using System;
    using System.IO;
    
    namespace Script
    {
      public partial class VuserClass
      {
        public int vuser_end()
        {
          lr.start_transaction("Unsubscribe Application");
          SampleDB.Unsubscribe();
          lr.end_transaction("Unsubscribe Application", lr.AUTO);
    
          lr.start_transaction("Deregister Application");
          //unregister and disconnect. make it block, so that it won't interfere with DeleteDatabase
          app.UnregisterApplication(TIMEOUT);
          lr.end_transaction("Deregister Application", lr.AUTO);
    
          //Cleanup
          try
          {
            if (SampleDB.DatabaseExists())
            {
              lr.start_transaction("DeleteDatabase");
              SampleDB.DeleteDatabase();
              lr.end_transaction("DeleteDatabase", lr.AUTO);
            }
          }
          catch
          {
          }
          //When debugging you might want to comment out this line to check MOCA log
          Directory.Delete(USER_DATA_DIRECTORY, true);
    
          return 0;
        }
      }
    }
  5. When running the test, observe or set the following runtime settings:
    • vuser must be run as a process
    • pacing allows you to specify multiple iterations for the code in Action.cs
    • think time can be used to simulate a more realistic usage scenario