In couple of my previous posts, I talked about what are the important events raised by test management service and how code for one such event listener looks like. In this post, I will talk about what exact steps I did to write my test management event listener. In case you are interested in writing one for your needs, you can follow similar steps.

Problem I need to solve

I want to find out all the test suites that are getting changed in my project, who is changing them and at what time they are getting changed. The changes in the suites could be of any form like creation of a new sub-suite, deletion of a sub-suite, addition/removal of tests in a suite etc.

Which event could help?

For the above problem, I looked at the important events which are exposed by the server, studied all of them and concluded that I need to listen to TestSuiteChangedNotification as it is raised when-ever a test suite is changed.

Writing the listener

Let us start with the main steps that I followed to create my listener.

  • Created a new c# class library project (The name of my project is TestSuiteEventListener).
  • Added a reference of following binaries to the project.
    • Microsoft.TeamFoundation.Framework.Server.dll
    • Microsoft.TeamFoundation.TestManagement.Server.dll
    • Microsoft.TeamFoundation.Common.dll

Note: – The first 2 binaries are not present with the Visual Studio installation, so I had to copy it from my team foundation server installation.

  • Implemented the ISubscriber interface in this library project. Let us briefly look at the important code snippets of this implementation.

 

    • Specified the event which I want to listen on using the following code snippet.

    public Type[] SubscribedTypes()
    {
        return new Type[] { typeof(TestSuiteChangedNotification) };
    }

    • Discarded all the events, other than the TestSuiteChangedNotification just in case framework gives it to the listener.

public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
     …   

     // Not a notification => no need to do anything
    if (notificationType != NotificationType.Notification)
    {
        return EventNotificationStatus.ActionPermitted;
    }

    // no suite change notification => no need to do anything
    TestSuiteChangedNotification suiteChangedNotification = notificationEventArgs as TestSuiteChangedNotification;
    if (suiteChangedNotification == null)
    {
        return EventNotificationStatus.ActionPermitted;
    }

    // if parameters are not valid => no need to do anything
    if (string.IsNullOrEmpty(suiteChangedNotification.ProjectName)
            ||
       suiteChangedNotification.SuiteId <= 0)
    {
        return EventNotificationStatus.ActionPermitted;
    }

    • Created a connection back to the server to find more data corresponding to TestSuiteChangedNotification.

/// <summary>
/// Get the tfs collection url
/// </summary>
private static string GetCollectionUrl(TeamFoundationRequestContext requestContext)
{
    TeamFoundationLocationService locationService = requestContext.GetService<TeamFoundationLocationService>();
    return locationService.GetHostLocation(requestContext, locationService.GetServerAccessMapping(requestContext));
}

using (TfsTeamProjectCollection collection = new TfsTeamProjectCollection(new Uri(collectionurl)))
{
    ITestManagementService tcm = collection.GetService<ITestManagementService>();
    ITestManagementTeamProject project = tcm.GetTeamProject(projectName);

    ITestSuiteBase suite = project.TestSuites.Find(suiteId);

    • Logged the required data in tfs server’s event logs. 

    string message = string.Format("Suite '{0}' (Id={1} under plan '{2}' in project '{3}') was modified by {4} at {5}",
                            suite.Title, suite.Id, suite.Plan.Name, projectName, suite.LastUpdatedByName, suite.LastUpdated);
    TeamFoundationApplication.Log(message, 123, System.Diagnostics.EventLogEntryType.Information);

This completes the implementation of the interface.

  • Copied the listener to the plugins directory of the tfs server  (C:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\Web Services\bin\Plugins)

This completes the development and deployment. Now I tried changing few things in my suites and observed that corresponding events are getting logged in the server event logs.

Thanks for reading and looking forward to your real custom listeners.

Here is the complete sample code along with the binaries just in case you want to use to get started on it quickly. Note that this sample will work only on Tfs 2012 server.

- Aseem Bansal