Accessibility

Table of Contents

Performance Testing Flex Applications That Use AMF

Recording Scripts

When you are ready to record a script, make sure you are set up with the right starting state for your data and browser URL so you won't have to hop around or add/delete records at the beginning of your recording. Then simply record yourself executing your test. Segue does the rest at assembling your script based on all the network traffic you generate.

Planning Your Scripts

The first thing you want to do is build up a set of scripts that model the user load on your Flex application. Consider recording a few scripts you can combine in different ways to simulate real user load. For example, if your application requires a login, you might make several scripts:

  • Log in, look up a record, and log out
  • Log in, add a record, and log out
  • Log in, print a report, and log out

Next add variability and loops to these scripts to simulate the natural variability you will see in your Flex application usage. For example, you may set the first script to log in, look up records a random number of times, and then log out. As you ramp up virtual users, each user will look up a different number of records before logging out, just as your real user population will. Of course, you have control over how to skew the randomness so that you can make it look like your real user population.

If your application does not have login and session management, you can actually structure your scripts in a different, simpler way:

  • Log in
  • Look up a record
  • Add a record
  • Print a record
  • Log out

Then you can have each virtual user chain together different, random patterns of logging in, then either looking up, adding, or printing, then logging out. Add to that the natural, random variability for the number of lookups, adds, and prints, and you have a very good real user simulation indeed.

For this article, I use the Restaurant Finder application by Christophe Coenraets. You can read about and download this application on his website. In this application, a typical user might select a region to list restaurants and then browse the list of restaurants. You will use that to model typical user behavior.

Making Your Recordings

Any tool can record HTTP traffic and display a readable, editable script. Performance-testing tools have been supporting HTTP, XML, and web services for a long time and they will all work well for you if you use those protocols. When it comes to recording scripts against your Flex AMF application, however, you will begin to appreciate the extra integration that Segue has built into Silk Performer.

When you use AMF, communications between the client and server occur in a binary, compressed format. Recording AMF scripts without the integration built into Segue Silk Performer yields scripts full of binary hex codes. This is impossible to read and edit. For example, you could probably spot where the script was getting information from the server and correlate that to your actions but you would not be able to read the specific communications back and forth. This is a problem because you cannot verify that the script worked correctly when you play it back under load, and you cannot edit the script to provide the natural variability that you would anticipate in a real pool of users.

For example, if you record a test script against a Flex application using AMF without special integration, you will see something like this:

    WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway", 
      "\h000000000001003373616D706C65732E" // •••••••3samples. 00000000  
      "\h72657374617572616E742E5265737461" // restaurant.Resta 00000010  
      "\h7572616E74536572766963652E676574" // urantService.get 00000020  
      "\h52657374617572616E747300022F3100" // Restaurants••/1• 00000030  
      "\h0000050A00000000",                // ••••••••         00000040  
      STRING_COMPLETE, "application/x-amf");
    WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway", 
      "\h000000000001003273616D706C65732E" // •••••••2samples. 00000000  
      "\h72657374617572616E742E5265737461" // restaurant.Resta 00000010  
      "\h7572616E74536572766963652E676574" // urantService.get 00000020  
      "\h52657374617572616E7400022F320000" // Restaurant••/2•• 00000030  
      "\h000E0A0000000100404A800000000000" // ••••••••@J•••••• 00000040  
      , STRING_COMPLETE, "application/x-amf");
    WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/addis.jpg");
    WebUrlEndPage(); // flex-internal

    ThinkTime(46.5);
    WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway", 
      "\h000000000001003273616D706C65732E" // •••••••2samples. 00000000  
      "\h72657374617572616E742E5265737461" // restaurant.Resta 00000010  
      "\h7572616E74536572766963652E676574" // urantService.get 00000020  
      "\h52657374617572616E7400022F330000" // Restaurant••/3•• 00000030  
      "\h000E0A0000000100404D000000000000" // ••••••••@M•••••• 00000040  
      , STRING_COMPLETE, "application/x-amf", 0.37);
    WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/aquitaine.jpg", 10.16);
    WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway", 
      "\h000000000001003273616D706C65732E" // •••••••2samples. 00000000  
      "\h72657374617572616E742E5265737461" // restaurant.Resta 00000010  
      "\h7572616E74536572766963652E676574" // urantService.get 00000020  
      "\h52657374617572616E7400022F340000" // Restaurant••/4•• 00000030  
      "\h000E0A0000000100404C000000000000" // ••••••••@L•••••• 00000040  
      , STRING_COMPLETE, "application/x-amf", 0.34);
    WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/argana.jpg", 8.48);
    WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway", 
      "\h000000000001003273616D706C65732E" // •••••••2samples. 00000000  
      "\h72657374617572616E742E5265737461" // restaurant.Resta 00000010  
      "\h7572616E74536572766963652E676574" // urantService.get 00000020  
      "\h52657374617572616E7400022F350000" // Restaurant••/5•• 00000030  
      "\h000E0A0000000100404F800000000000" // ••••••••@O•••••• 00000040  
      , STRING_COMPLETE, "application/x-amf", 0.36);
    WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/aspasia.jpg", 9.46);
    WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway", 
      "\h000000000001003273616D706C65732E" // •••••••2samples. 00000000  
      "\h72657374617572616E742E5265737461" // restaurant.Resta 00000010  
      "\h7572616E74536572766963652E676574" // urantService.get 00000020  
      "\h52657374617572616E7400022F360000" // Restaurant••/6•• 00000030  
      "\h000E0A0000000100404A000000000000" // ••••••••@J•••••• 00000040  
      , STRING_COMPLETE, "application/x-amf", 0.30);
    WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/atasca.jpg");

View color-coded example

By using Segue Silk Performer support for Flex AMF and recording the same script, however, you can see a readable, editable script that will serve you well:

    WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
      "<SegueAmfXml version=\"0\">\r\n"
      "  <Msg length=\"5\"\r\n"
      "       operation=\"samples.restaurant.RestaurantService.getRestaurants\"\r\n"
      "       responseURI=\"/1\">\r\n"
      "    <StrictArray nrElems=\"0\"></StrictArray>\r\n"
      "  </Msg>\r\n"
      "</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurants");
 
    WebPageAddUrl("restaurant/assets/pic/addis.jpg");
    WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
      "<SegueAmfXml version=\"0\">\r\n"
      "  <Msg length=\"14\"\r\n"
      "       operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
      "       responseURI=\"/2\">\r\n"
      "    <StrictArray nrElems=\"1\">\r\n"
      "      <Number>53</Number>\r\n"
      "    </StrictArray>\r\n"
      "  </Msg>\r\n"
      "</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant");
 
    WebPageAddUrl("restaurant/assets/pic/aquitaine.jpg");
    ThinkTime(11.8);
    WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
      "<SegueAmfXml version=\"0\">\r\n"
      "  <Msg length=\"14\"\r\n"
      "       operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
      "       responseURI=\"/3\">\r\n"
      "    <StrictArray nrElems=\"1\">\r\n"
      "      <Number>58</Number>\r\n"
      "    </StrictArray>\r\n"
      "  </Msg>\r\n"
      "</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#1)");
 
    WebPageAddUrl("restaurant/assets/pic/argana.jpg");
    ThinkTime(2.2);
    WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
      "<SegueAmfXml version=\"0\">\r\n"
      "  <Msg length=\"14\"\r\n"
      "       operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
      "       responseURI=\"/4\">\r\n"
      "    <StrictArray nrElems=\"1\">\r\n"
      "      <Number>56</Number>\r\n"
      "    </StrictArray>\r\n"
      "  </Msg>\r\n"
      "</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#2)");
 
    WebPageAddUrl("restaurant/assets/pic/aspasia.jpg");
    ThinkTime(2.4);
    WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
      "<SegueAmfXml version=\"0\">\r\n"
      "  <Msg length=\"14\"\r\n"
      "       operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
      "       responseURI=\"/5\">\r\n"
      "    <StrictArray nrElems=\"1\">\r\n"
      "      <Number>63</Number>\r\n"
      "    </StrictArray>\r\n"
      "  </Msg>\r\n"
      "</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#3)");
 
    WebPageAddUrl("restaurant/assets/pic/atasca.jpg");
    ThinkTime(2.5);
    WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
      "<SegueAmfXml version=\"0\">\r\n"
      "  <Msg length=\"14\"\r\n"
      "       operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
      "       responseURI=\"/6\">\r\n"
      "    <StrictArray nrElems=\"1\">\r\n"
      "      <Number>52</Number>\r\n"
      "    </StrictArray>\r\n"
      "  </Msg>\r\n"
      "</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#4)");

View color-coded example

Obviously, the Segue script created with built-in support for AMF is much more editable and usable.

When you record your script, it's helpful to plan the recording so you can execute it cleanly. Real users do not execute all scripts cleanly. However, you can provide natural variability in other ways, such as varying think times and playing scripts to add random noise. By recording clean scripts, you can edit the scripts more effectively and have more exact control over the load you are creating when you play back.

It's also helpful to add comments to your script while you are recording. You might add a comment, such as "Opening restaurant review" and "Restaurant review opened," to delineate clearly the request and response from the server. You also may want to use Silk Performer's transaction markers to indicate the beginning and end of a transaction so you can report on end-user transactions as a whole rather than as a series of client/server communications.