This blog has moved, permanently, to http://software.safish.com.

Tuesday, October 6, 2009

.NET Assembly Probing

I hate the way Windows Forms applications get built with all their binaries in a single folder. I also hate the publish options in Visual Studio - those crappy .application files stink in so many ways. I prefer to just deploy the executable and related assemblies using some kind of packaging tool.

The problem here is all the dll's by default need to be in the base appdomain directory, which can end up being a horrible mess in the base install directory. There is a configuration option you can use with your application, though, to tell it to search in other folders for required assemblies, like so:

  
    
      
    
  

WatiN with CruiseControl running as a service

We've started using WatiN for our automated tests: nice and easy to use and integrates easily, but I did hit one stumbling block: CruiseControl.NET. When running tests locally, there were no issues - check the code in and bang, the tests fail. It was immediately apparent that it was a security thing - the CruiseControl.NET service runs by default with the SYSTEM user, but I could find little to no help anywhere on how to set this up correctly.

One solution was to just tick the service option to "Allow service to interact with the desktop", but this didn't work for me - the failure remained the same when the browser instance was being created.

It took a few hours of testing (I ended up using a local Scheduled Task to test this out) and I finally found a fairly easy way to get it to work - on your build server you need to use a local account that the service runs under. I used a local admin account - you might not be able to do this in which case you're on your own (it'll still work - you'll just need to be more careful about how you apply permissions), but the steps to set this up are as follows:
  • Create a local admin account (e.g. CCAdmin) - make sure you set it so the password does not need to be changed and does not expire
  • Log out, and log back in using the new account
  • Open up IE (or whatever your testing browser is) and go through all the dialog screens. Set the home page to blank. If you're using Firefox, make sure all the required plugins are installed.
  • Open up services.msc (Start...Run....services.msc), and stop the CruiseControl.NET service. Right-click and go to Properties
  • Go to the Log On tab, and instead of a Local System account, set it so the service uses your new account
  • If you have not created an admin account, make sure the account has all necessary security permissions
  • Click OK, and fire up the service again

Tuesday, September 29, 2009

WatIn

I've been fighting with Selenium and automated testing lately, and I just couldn't shake the feeling that it just wasn't the right tool for the job. The IDE is flakey in terms of files you save (making changes to the project often results in JS errors in the tests), the server is a java server which I had to jump through hoops to get running as a Windows service, and the loading of a browser for the tests is hellishly slow.

It really is a great tool, and I love it's ease of use for development (I use it to autocomplete forms instead of typing all that crap in over and over again), but as an automated testing suite on a Windows technology stack, I'm just not a huge fan.

So today, I downloaded WatIn and gave it a run. I had the automated nUnit side up and running in a matter of minutes - the tests ran fast and the API is intuitive and easy to use.

The test recorder is not as good as Selenium's, but it's decent enough, and there is a beta version out that is supposed to be a vast improvement. I did download and try the Beta version, but it wouldn't even run for me, so I guess it's REALLY in Beta. Anyway, I'm more interested in the CruiseControl automated side of testing than visual testing, so it's easy, understandable unit test code that I want to be able to produce - and for this WatIn wins hands down.

Friday, September 18, 2009

Running Selenium RC as a Windows Service

We've recently started using Selenium as a testing tool at work. The IDE is great, particularly for filling in forms during development, but I'm a stickler for automated testing.

Selenium does off Selenium RC, which combined with nUnit allows for this in a variety of programming languages. The problem here, is that the server is a jar file, and I wanted it running as a windows service on our build server.

Anyway, I found a great article on tacktech.com that shows how to run just about anything as a windows service - and I successfully used that article to get Selenium RC running as windows service on our build server. Here are the steps:
  1. Install the latest Java runtime if you don't have it installed already
  2. Install the Selenium server (e.g. C:\Selenium\selenium-server-1.0.1
  3. Download srvany.exe and instsrv.exe (these are part of the Microsoft Windows Resource Kit - you will need to download the correct version for your OS) and copy these files to a location on your server (e.g. C:\reskit)
  4. Browse to this folder, and type: instsrv "Selenium RC" "C:\reskit\srvany.exe" - this will create the windows service named "Selenium RC", which will now be installed as a Windows service, although it won't start up yet
  5. Open up regedit, and browse to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Selenium RC
  6. Right-click "Selenium RC" in the tree, and click New - Key, and add a key called "Parameters"
  7. Open Parameters, and create a new string value called "Application"
  8. Add the following to the data value for the new string value: "C:\Program Files (x86)\Java\jre6\bin\java.exe" -jar "C:\Selenium\selenium-server-1.0.1\selenium-server.jar", substituting paths to the java exe and the selenium server jar file where appropriate
  9. Load up the windows services console (services.msc) and start the service

Thursday, September 10, 2009

SQL Server: Finding tables by column

Assuming you use a decent naming convention in your database, it's sometimes useful to be able to find a list of tables with a common column - for example if you want to write a script to clean out all data related to a specific item, referenced by foreign key columns of the same or a similar name.
 
SELECT distinct
    c.table_name,
    c.table_schema,
    c.column_name
  FROM 
    information_schema.columns c
    INNER JOIN information_schema.tables t 
      ON c.table_name = t.table_name 
  WHERE
    c.column_name LIKE '%my_column_name%'
    AND t.table_type = 'BASE TABLE'
  ORDER BY 
    c.table_name,
    c.column_name

Thursday, August 27, 2009

Roll on ASP.4

Scott Guthrie has started creating posts about the upcoming features of VS 2010 and .NET 4.

I've never been a Microsoft fanboy, but you have to give it to them, they really seem to have listened to their users the last few years as they continue to change all the issues people have griped about. The first two posts indicate more good things to come - the web.config files have been cleaned up (at last!) and now it appears there are some great project templates coming. What I am really excited about though is the complete control of client IDs that's coming - the whole UniqueID/ClientID pain in the ass has always bothered me about ASP.NET, and it looks like that has finally been addressed in .NET 4. Flubba dubba.

Friday, August 21, 2009

SQL Server: Currently Executing Queries

I found this great article by Ian Stirk on SQLServerCentral.com, regarding finding queries that are currently executing on SQL Server. The article contains the following VERY useful query:
    -- Do not lock anything, and do not get held up by any locks.
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

    -- What SQL Statements Are Currently Running?
    SELECT [Spid] = session_Id
 , ecid
 , [Database] = DB_NAME(sp.dbid)
 , [User] = nt_username
 , [Status] = er.status
 , [Wait] = wait_type
 , [Individual Query] = SUBSTRING (qt.text, 
             er.statement_start_offset/2,
 (CASE WHEN er.statement_end_offset = -1
        THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
  ELSE er.statement_end_offset END - 
                                er.statement_start_offset)/2)
 ,[Parent Query] = qt.text
 , Program = program_name
 , Hostname
 , nt_domain
 , start_time
    FROM sys.dm_exec_requests er
    INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
    CROSS APPLY sys.dm_exec_sql_text(er.sql_handle)as qt
    WHERE session_Id > 50              -- Ignore system spids.
    AND session_Id NOT IN (@@SPID)     -- Ignore this current statement.
    ORDER BY 1, 2