Application development and testing your code

Today I am going to touch on a subject that can all too importantly be overlooked, and regardless of whether it is open source or paid work there is an importance to releasing your code as bug free as you possibly can. I spent today trying to figure out why something that I had been using for a few years, had all of a sudden stopped working. I had patched this open source application to the newest version, which was about 5 versions ahead of what I was using.

When I began running a few tests on the patch before making it live, there was some very noticeable problems with the update. It just would no longer work in any way, and I noticed some very disturbing problems in the code that I had to ask the developer in question if they had done any testing on these changes. So without going into too much detail, I am going to use a few examples that will highlight the problem that I discovered in this case.

However before I do begin discussing this in more detail, I would also like to point out that Test Driven Development is all too important these days. And whether you are following the more adopted method of Unit Testing, or using your own approach it is important to test as much of your code as you can. Test Driven Development is about code coverage, and can highlight important changes that are made as either broken or not very quickly and very easily.

The problem that I faced was something that would have been picked up the moment it was first run, or at least given some basic test case scenario's in which neither appeared to have been made. My statement to this developer in asking if he could at least run some tests, was taken very offensively and politely said he would drop that support.

So what was the problem in this case, and why did it become an issue after I updated to the latest version?

The Application in question used an XML-RPC connection to the server to send packets of XML data across to the server, which then gave instructions on what to do from there. These packets also had embedded authentication credentials, that would be used to authenticate the process to make sure the request was made by someone who had the correct privileges.

So lets look at an example of what was happening and why it was not doing what it was supposed to do. A lot of unimportant code has been removed as it was not needed, the importance of the actual problem is what is important in this case.

<cfset username = requestData.params[2]>
<cfset password = requestData.params[3]>
<cfset bareData = requestData.params[4]>
<cfset published = requestData.params[5]>
<cfif structKeyExists(variables, "currentId")>
<cfset currentData = application.module.getData(currentID, true) />
</cfif>
<cfif application.module.authenticate(username, password)>
<cfloginuser name="#username#" password="#password#" roles="admin">
</cfif>

Now the above code at first glance would not actually show any real problems, so lets be clear on what this is doing first and then I'll describe why this is a bug that was never tested.

As you can see from the code the XML-RPC contains the username and password, which is then later used to make sure there is an authentication done. Now the problem with the above code, is that there is a call to getData which is used to check to see if the data already exists and if it does then we will revert to edit mode. But the problem is that the code for getData has the following line of code in it.

<cfif not isUserInRole("admin")>
and         posted < <cfqueryparam cfsqltype="cf_sql_timestamp" value="#now()#">
and         released = 1
</cfif>

So why is this a problem?

Well it becomes a problem because there is a check to see if the user belongs to the relevant role, because only the administrator can see anything that has been flagged as being in draft mode. So when we go back to the first code snippet, you will notice that the login code is after the call to check to see if we need to be in edit mode or new mode. So in this example if we just take the example above, the XML-RPC posted data would always be in new data mode and would never get into edit mode.

Now this wouldn't throw an error when the application is run, but it highlights that there is a bug in the code. Because if we do not test that we can also edit this data, then we will never know about the problem either and even though it would take just a few more seconds, it is important to run that test to see if it works as we intend it to work.

I wanted to write this post for a few reasons, one of those reasons is that the Application in question is open source. And I am afraid that just because it is open source, doesn't excuse the fact that there is a major bug in the logic in the above example and that the tests that would have picked this flaw in the logic were never run, and hence was never picked up.



  • marc esher's Gravatar writing open source software is an often thankless job. perhaps you could step up and contribute unit tests for this particular bug. maybe it'd turn into a 'stone soup' kind of deal.... you write one unit test to prove the bug exists, maybe you contribute a patch to fix it, and then maybe the suite of tests grows as the seed is planted.

    i mean, since it's open source and all.
    # Posted By marc esher | 3/29/09 11:36 AM
  • Andrew Scott's Gravatar Marc - I used that as an example to highlight the problem of not running your logic flow through standard tests. In this example, the cflogin was in the wrong spot, and as indicated you could never edit what was posted.

    That to me is a lack of testing your logical flow, and what is intended. Granted you can't test every known condition or we would be sitting on things for years on end trying to find a potential error. But when it is in plain sight and not tested, that is plain wrong.

    Don't take this as an attack on the original authour, take it as an awareness how important it is to test the most basic flow of your code first and foremost.
    # Posted By Andrew Scott | 3/29/09 11:54 AM
  • Raymond Camden's Gravatar One of the problems here is that I'm not convinced UTs would help. As I worked on XML-RPC support in BlogCFC (and a lot of it was contributed code actually), I discovered that 'spec' was a very lose term. Almost every client did things a different way. There is NO way UTs would be able to handle all the particular use cases in terms of how different clients 'talk' to an XML-RPC compliant blog.

    When I mentioned dropping support - that was a comment made out of frustration. Working with XML-RPC is extremely difficult. As soon as it works for one client, it tends to break for another one. When I said I'd just drop it, that was partially in response to what I felt was rudeness from you, but mostly from just being tired of the feature in general. What I'm considering is NOT dropping the feature, but picking 2-3 clients to support and thats it. Period. It sucks to say that because, again, XML-RPC should be a spec that all clients respect, but that is simply not the case. The clients I do pick will have to be free ones though (unless someone wants to contribute).
    # Posted By Raymond Camden | 3/29/09 12:07 PM
  • Andrew Scott's Gravatar @Ray you maybe right on the UT side, because in this case you would have to write the UT's in sellenium or something and evnetually write your own blog writing application.

    However, my point on not testing to edit a new post is the issue in question. As well as the other issue regarding the structfind as I noted to you, and in that case unless that method is run that structure is not setup. Unlikely true, but it is created as an empty struct and never populated. So that could have been tested too, but I hope you don't mind me bringing this here because I wanted to highlight to others how testing even it is basic application flow testing, can I post an entry can I edit an entry. Was to highlight how that was skipped, and never got tested to see if it actually worked.

    As for contribution, I am more than happy to as already indicated to you once I am happy with what I have done pass it on to you for your inclusion or further testing by others. So I am more than happy to help out here.
    # Posted By Andrew Scott | 3/29/09 12:17 PM
  • Raymond Camden's Gravatar I'm not sure I'll ever be happy doing testing with XML-RPC clients. I just don't care for em. But again, if I can get it down to a list of 1 or 2, I'd be happy to add that to my 'normal' test suite.
    # Posted By Raymond Camden | 3/29/09 12:25 PM
  • Andrew Scott's Gravatar @Ray - I am currently setting up a UT case for Microsoft as we speak, the reason being is that as I posted in the ticket. I can't run Winodws Live Writer, under Windows 7 and post a new blog nor edit it with BlogCFC.

    I thought the problem might have originally have been BlogCFC, but when I got it to work under Windows Vista it was like WTF!!

    Anyway I have captured certain xml packets that can be used for UT's, and will include these in what I give you down the track.

    But like I said in my post, it is not about the XML-RPC clients. But I know what you mean by how everyone is different, and I have used WLW as a benchmark for testing because it seems to more stable than anything else that I have used.

    # Posted By Andrew Scott | 3/29/09 12:35 PM
  • Dan G. Switzer, II's Gravatar @Andrew:

    I recently resolved this exact issue and I'm going to send my patches to Raymond.
    # Posted By Dan G. Switzer, II | 3/29/09 5:41 PM