Developer Forums | About Us | Site Map
Search  
HOME > TUTORIALS > SERVER SIDE CODING > PYTHON TUTORIALS > WEB APPLICATION TESTING WITH PUFFIN: PART 2


Sponsors





Useful Lists

Web Host
site hosted by netplex

Online Manuals

Web application testing with Puffin: Part 2
By Keyton Weissinger - 2004-06-03 Page:  1 2 3 4 5

Tasks and plans

A task is a grouping of actions that fail or succeed as a group. A plan is an ordered list of tasks that instructs Puffin how to execute the tasks. The best way to understand both is to see a brief example.

Listing 6 is a simple plan called simplePlan.txt:

Listing 6. Simple plan

# This is a comment in the simple plan file. Puffin ignores it.
setLoginInfo
login
getSalesByUser

But wait! These aren't tasks. These are just the actions we defined in the last section. In the simple plan format you simply list actions you wish Puffin to execute, and Puffin executes them one after another. It won't stop if one fails, but it will manage inputs/outputs as described in the last section. Simple format plans are useful for testing actions and for simple setups where very little is involved in running your plan.

Just for information, Puffin really does treat these individual elements as tasks, just tasks that involve the execution of only a single action apiece. You don't need to worry about that, though, as that happens in the background.

Now the action definitions plus this simple format for plans is of some use in simple scenarios, but often you would like to short-circuit the process if something fails. For example, it is useless to have Puffin execute the getSalesByUser action if the USER_ID output is not successfully extracted from the results of the login action.

This is where the advanced plan format comes into play. The advanced plan format allows you to wrap one or more actions into a task element that Puffin executes as a unit. All its actions must succeed for the wrapper task to succeed.

Listing 7 puts the setLoginInfo and login actions together into a task in an advanced plan:

Listing 7. Advanced plan

<plan>
  <task name="login">


      <action name="setLoginInfo"/>
      <action name="login"/>
   </task>
</plan>

You now have a login task made up of the two actions setLoginInfo and login. For this task to succeed, both setLoginInfo and login will both have to succeed.

Now add a second task. This second task will be made up of only the getSalesByUser action, but it will be dependent on the login task above:

Listing 8. getSalesByUser action

<plan>
  <task name="login">
      <action name="setLoginInfo"/>
      <action name="login"/>
   </task>


   <task name="getSalesByUser" dependsList="login"/>
</plan>

This second task demonstrates two things. The first is the abbreviated format for tasks in an advanced plan that contain only a single action. The second is the inclusion of the dependsList attribute. This attribute instructs Puffin that the getSalesByUser task should be executed only if the tasks (comma-separated) listed in the dependsList attribute all succeed.

That's enough on tasks for now. Let's look at some other powerful features for advanced plans. The first is the repetition of tasks.

I should warn the XML seniors among you that the <repeat> tag makes for UGLY xml. However, it allows for some incredibly powerful execution scenarios. If you want to repeat a task, all that is required is for you to insert that task inside a repeat tag like this:

Listing 9. Repeat a task

<plan>
   <task name="login">
      <action name="setLoginInfo"/>
      <action name="login"/>

   </task>

   <repeat name="salesQueryRepeat" count="2">
      <task name="getSalesByUser" dependsList="login"/>
   </repeat>
</plan>

You can wrap any task or group of tasks in a repeat tag. The repeat tag can have a name attribute (optional), which is used in reporting, and a second attribute that indicates when Puffin should stop repeating the contents of this repeat tag. The example above uses a count attribute to indicate to Puffin that it should execute the getSalesByUser task twice.

The count will do what you need in most cases. There are also while and until repeat attributes that take the name of an action token as a value. These work on whether the token evaluates to TRUE or FALSE as you'd predict. For example, suppose you want to run a set of tasks that affect every record in a table one at a time. At the end of these tasks, one of the outputs updates an action token with the remaining records. If that token evaluates to TRUE (there are more records), you want it to repeat. If not, you want it to stop. In this case, you'd use a while attribute in the repeat tag.

There are other features of the repeat tag (including the ability to repeat a task or set of tasks until one fails, for example), and you can, of course, include a repeat inside other repeat tags. Needless to say, the use of repeat tags can make for some very complex and powerful Puffin plans.

As a last example of a plan file, take a look at this advanced plan (from the Puffin distribution) in Listing 10:

Listing 10. Complex plan

<plan>
   <repeat name="repeat1" count="1">
      <task name="login">

         <action name="resetInventory"/>
         <action name="login"/>

         <action name="loginAquilaSuccess"/>
      </task>
      
      <repeat name="repeat2" count="2">
         <task name="makeDecision" dependsList="login">

            <action name="selectRandomCategory"/>
            <action name="getItemLists"/>

            <action name="selectItem"/>
         </task>
         <repeat name="repeat3" count="2">
            <task name="makePurchase" dependsList="makeDecision">

               <action name="generateSelectionCount"/>
               <action name="addItemToCart"/>

               <action name="updateCurrentSelection"/>
               <action name="showCart"/>
               <action name="getUpdatedInventory"/>
            </task>

         </repeat>
      </repeat>

      <task name="checkOut" dependsList="makePurchase"/>
   </repeat>
</plan>

Spend some time looking into this plan when you start working seriously with Puffin. Until then, use the simple format.

Before leaving plans, I want to introduce one last concept. Many Puffin users have indicated that they want to be able to extend the framework in Python and thus completely control how plans are executed. This allows you even more flexible control over plans and task execution. Until I can cover this topic in a future article, I will simply say that the Puffin plan is a class called (not surprisingly) Plan. This plan can be subclassed to make your very own custom plan class, like this one shown in Listing 11 (special thanks to Webware's Chuck Esterbrook for his suggestions on how this should work):

Listing 11. Puffin plan

from paf.core.plan import Plan
from mystuff import starsAligned

class CustomPlan(Plan):
    
    def __init__(self, workSpace='default'):
        Plan.__init__(self, workSpace)

    def executePlan(self):
        #1. First, lets load some tasks.
        self.loadTask('login',
                      actionNameList=['setLoginInfo','login'])
        self.loadTask('getSalesByUser', 
                      actionNameList=['getSalesByUser'],
                      dependsList=['login'])
        if starsAligned():
           self.executeTask('login')
           self.executeTask('getSalesByUser')

if __name__ == "__main__":
    myPlan = CustomPlan()
    myPlan.execute()

If you don't know (or care) about Python, you can safely skip to Results processing below (though I strongly encourage to try Python and come back!).

Listing 11 is a simple subclassing of the Puffin Plan class, paf.core.plan.Plan. With this subclass, you have everything that the Puffin framework gives you (tasks, task dependencies, etc). For example, even if you use executeTask to execute the getSalesByUser task, Puffin will handle dependencies (such as not executing that task if the login task failed) and other complexities. However, in this example, you can see how I've introduced my own spin on execution.

In this example, if my starsAligned() method comes back false, then the task execution isn't attempted. Although a simple example, you can see how subclassing Plan will allow you very powerful control over how Puffin handles your tasks.

To execute the custom plan, you must call the execute() method, but override the executePlan() method. The execute() method (part of the Plan base class) handles initialization of the various results-processing mechanisms (described in the next section) and some other housecleaning chores.



View Web application testing with Puffin: Part 2 Discussion

Page:  1 2 3 4 5 Next Page: Results processing

First published by IBM developerWorks


Copyright 2004-2024 GrindingGears.com. All rights reserved.
Article copyright and all rights retained by the author.