Powershell: handy links

December 12, 2011

Run integration tests with TFS2010. Part 1.

October 21, 2011

Last week I was working on automation of regression tests for our product. We have some NUnit tests that were run manually by nunit console on the virtual machine with our product installed. The goal was to automate this process and store results somewhere. We use TFS 2010 and did not want to bring another third party tool for continuous integration process on the other hand we wanted to use the existing tests and bring minimum change to them.

  1. We decided to create a new build definition that will run tests remotely and publish test results to the TFS.
  2. To run tests remotely we decided to use Powershell with invoke-command -computername to run powershell script which can call NUnit.
  3. To be able to publish NUnit’s test results, an xslt tranformation is needed which can be taken from nunit4teambuild.codeplex.com

I will write separate posts for each of this steps in a short time as there were some challenges on each step.

Client performance: enabling KeepAlive

June 10, 2011

The Keep-Alive extension to HTTP/1.0 and the persistent connection feature of HTTP/1.1 provide long-lived HTTP sessions which allow multiple requests to be sent over the same TCP connection. In some cases this has been shown to result in an almost 50% speedup in latency times for HTML documents with many images. (source)

Apache configuration:


KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout  5

Before KeepAlive:

http://gdestop.ru:

gdestop

http://gdestop.ru/adler:

adler

http://gdestop.ru/anapa/view/492:

hotel

Before KeepAlive:

http://gdestop.ru:

gdestop

http://gdestop.ru/adler:

adler

http://gdestop.ru/anapa/view/492:

hotel

For some pages enabling KeepAlive worked out better fot some worse, but generally it’s recommended to enable KeepAlive. My additional advice is to monitor server’s resource usage after each reconfiguration.

  • gdestop
  • adler
  • hotel

Client performance: adding gzip compression

June 6, 2011

As a continuation of client side optimization let’s now find out how enabling gzip compression between server and client affects page loading.

First, one needs to enable mod_gzip for Apache (I’m using it) and configure it the proper way. Usually it’s reasonable to compress text content such as css or js files, as well as html response. Compressing images is usually considered as waste of CPU, so we should not allow it.

Here is my mod_gzip configuration file (thanks to this post):


mod_gzip_on                   Yes
mod_gzip_can_negotiate        Yes
mod_gzip_static_suffix        .gz
AddEncoding              gzip .gz
mod_gzip_update_static        No
mod_gzip_command_version      '/mod_gzip_status'
mod_gzip_temp_dir             /tmp
mod_gzip_keep_workfiles       No
mod_gzip_minimum_file_size    300
mod_gzip_maximum_file_size    500000
mod_gzip_maximum_inmem_size   60000
mod_gzip_min_http             1000
mod_gzip_handle_methods        GET POST
mod_gzip_dechunk              Yes
mod_gzip_send_vary            On

#Files and items to compress
mod_gzip_item_include         file       \.html$
mod_gzip_item_include         file       \.htm$
mod_gzip_item_include         file       \.js$
mod_gzip_item_include         file       \.js
mod_gzip_item_include         file       \.faces
mod_gzip_item_include         file       \.css$
mod_gzip_item_include         file       \.jsp$
mod_gzip_item_include         file       \.jsp

mod_gzip_item_include         uri        \.jsp$
mod_gzip_item_include         uri        \.jsp

mod_gzip_item_include         handler    \.*
mod_gzip_item_include         handler    \.*$

mod_gzip_item_include         mime       ^text/html$
mod_gzip_item_include         mime       ^text/html
mod_gzip_item_include         mime       ^text/plain
mod_gzip_item_include         mime       ^text/plain$
mod_gzip_item_include         mime       ^text/xml$
mod_gzip_item_include         mime       ^text/css$
mod_gzip_item_include         mime       ^text/javascript$
mod_gzip_item_include         mime       ^text/javascript
mod_gzip_item_include         mime       ^application/x-javascript$
mod_gzip_item_include         mime       ^application/javascript$

also this file has to be included in the apache configuration file by using the Include statement. To make a django application sending compressed response, the middleware list must contain django.middleware.gzip.GZipMiddleware in settings.py:

MIDDLEWARE_CLASSES = (
	'django.middleware.gzip.GZipMiddleware',
        'django.middleware.common.CommonMiddleware',
...
)

After doing that a Firebug can be used to see that content is compressed by the response headers:

ffgzip

Now lets run TestWebPage against my key pages from the previous post:

Before gzip

http://gdestop.ru:

gdestop-cdn

http://gdestop.ru/adler:

adler-cdn

http://gdestop.ru/anapa/view/492:

hotel-cdn

After gzip:

http://gdestop.ru:

gdestop

http://gdestop.ru/adler:

adler

http://gdestop.ru/anapa/view/492:

hotel

So, we have very good results for the root page, and resort’s page. Hotel’s page did get such a good boost because when I moved all common scripts to CDN, they became compressed by CDN.

  • ffgzip
  • gdestop
  • adler
  • hotel

Up to 30% loding page faster by using CDN

June 2, 2011

I decided to begin client optimization for http://gdestop.ru First I’ve become really interested in it and second now over 1700 unique visitors come every day, so it would be nice to care about them and decrease page loading time.
To be able compare the optimization results, I’ve run WebPagetest for three key pages (all of them in Russian, so sorry for non-Russian speakers): http://gdestop.ru (the root page – does not have many scripts comparing to others), http://gdestop.ru/adler/ – (resort’s page – has jQuery UI + YUI data table) and http://gdestop.ru/anapa/view/492/ – a typical hotel’s page with lots of jQuery UI plugins + YUI, the heaviest one. Tests were run for Moscow, IE8 :

http://gdestop.ru:

gdestop

http://gdestop.ru/adler:

adler

http://gdestop.ru/anapa/view/492:

hotel

Not the best results though, but I really did not care much about client side optimization. All scripts were hosted locally and let’s see how things change if I move common scripts (jQuery, jQuery Ui, YUI) to CDN. I decided to use Yandex CDN http://api.yandex.ru/jslibs/ as for Russia I believe this is the most appropriate.

http://gdestop.ru:

gdestop-cdn

http://gdestop.ru/adler:

adler-cdn

http://gdestop.ru/anapa/view/492:

hotel-cdn

As we can see, moving to CDN made 30% faster first view for the root page and hotel’s which is a really great result for such a little effort.

To be continued…

  • gdestop
  • hotel
  • gdestop-cdn
  • adler-cdn
  • adler
  • hotel-cdn

HOWTO: Add global ajax event handlers with jQuery

May 30, 2011

Task: add global state for selenium tests to wait for when ui is very ajax based.


//javascript

var _Busy = false;

function setBusy(flag) {
    _Busy = flag;
}

function isBusy() {
    return _Busy;
}

$(document).ajaxStart(function () {
    setBusy(true);
});

$(document).ajaxStop(function () {
    setBusy(false);
});

//C# - selenium wrapper

public void WaitForUiReady()
{
    _selenium.WaitForCondition("selenium.browserbot.getUserWindow().isBusy() == false", PageLoadTimeOut);
}

HOWTO: Required field visualization with Html.LabelFor

May 16, 2011

Based on http://weblogs.asp.net/raduenuca/archive/2011/02/17/asp-net-mvc-display-visual-hints-for-the-required-fields-in-your-model.aspx

My solution:

namespace WebUI.Extensions
{
    public static class LabelExtensions
    {
        public static MvcHtmlString LabelForEx(this HtmlHelper helper, Expression> expression)
        {
            var metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);

            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metaData.DisplayName ?? metaData.PropertyName ?? htmlFieldName.Split('.').Last();            

            if (String.IsNullOrEmpty(labelText))
                return MvcHtmlString.Empty;

            var label = new TagBuilder("label");
            label.Attributes.Add("for", helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

            bool isRequired =
                metaData.ContainerType.GetProperty(metaData.PropertyName)
                    .GetCustomAttributes(typeof (RequiredAttribute), false)
                    .Length == 1;

            if (isRequired)
                label.Attributes.Add("class", "required");

            label.SetInnerText(labelText);
            return MvcHtmlString.Create(label.ToString());
        }
    }
}
label.required:after {
    color: red;
    content: "*";
}
<%= Html.LabelForEx(model => model.FieldName)%>

HOWTO: Integrate Visual Studio and DiffMerge

April 25, 2011

Go to Tools->Options /Source Countrol/VSTFS-Configure User Tools…

View:

.*
C:\Program Files (x86)\SourceGear\DiffMerge\DiffMerge.exe
/title1=%6 /title2=%7 %1 %2

Merge:

.*
C:\Program Files (x86)\SourceGear\DiffMerge\DiffMerge.exe
/title1=%6 /title2=%8 /title3=%7 /result=%4 %1 %3 %2

Remove duplicate categories urls.

January 13, 2011

I’ve discovered that WordPress generates the same category page for http://exapmple.com/category/child and http://exapmple.com/category/parent/child which is not so good for SEO. The possible quick fix that worked for me – to add to the theme’s header.php the following code:

if (is_category())
{
	list($dummy, $categoryRelative) = split("category", $_SERVER["REQUEST_URI"]);

	$category_id = get_cat_ID( single_cat_title("", false) );
	$category_link = get_category_link( $category_id );

	list($dummy, $correctCategoryRelative) = split("category", $category_link);

	if ($categoryRelative != $correctCategoryRelative)
	{
		header('HTTP/1.1 301 Moved Permanently');
		header('Location: '.$category_link);
		exit();
	}
}

This is a really quick code – if you can suggest a better solution, please do!

wordpress: change rss feed order

December 24, 2010

For some reason I needed my rss feed to sorted not by post date, but by posts’ id as I could have newer post with not the latest post date (some future posts that stll had publish status). To change the rss feed’s order I’ve hooked pre_get_posts:


add_action('pre_get_posts', 'sort_rss' );

function sort_rss( $notused )
{
	global $wp_query;
	if( is_feed() )
	{
		$wp_query->set( 'orderby', 'ID' );
	}
}

That worked for me. Have better solution? Write a comment!

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org