Johan Antila
Sep 4, 2019
  6284
(2 votes)

Scripted testing of IIS URL Rewrite rules

On most websites today you are likely to need to rewrite urls to match a specific requirement such as the typical SEO rules where you need urls to all end with a trailing slash and be all lowercase to prevent duplicate content in the search engines or add a few hard coded redirects for old discontinued sites. While these rules by themselves are easy enough to test, as soon as you start creating a few more rules and they contain host names, you will get a bit of a challenge to test these locally.
While it is possible to test the rules locally in the IIS Administration tool, this is only an atomic test of the single rule and not a test of the entire redirect pipeline so if you introduce one bad rule, you can't tell if it breaks the other redirects unless you request it with a browser through IIS and with a lot of urls, this becomes increasingly impractical and in the scenario where you yourself aren't handling the go-live and you haven't been able to test the rules locally, it creates the need to write these same rules as a human readable script for whoever is doing the deploy/rollback to test after applying the change. If only there was a way to script this. Well there is.
Using nodejs with puppeteer, you can easily create a test script in which you define all your urls you want to test and see if they are redirecting as expected.

First you need to install nodejs if you haven't already done that, then in a console window, install puppeteer , a module to programmatically control googles Headless Chrome.

npm install puppeteer

With puppeteer you can do all sorts of things with automatic testing and we are going to use it in a pretty simple way, let it navigate to a url and see what url it ends up on and test if we were expecting this url. The nice thing here is that we're testing what a browser would actually do after it has completed all the redirects, even ones you've written in code for redirecting users based on geo-ip for instance and if you have a redirect loop here, you will get an error.

Now you need to make sure you have all the redirect rules in place for production in your local dev environment, ie, in web.config and if you're not comfortable with having these rules permanently in your development environment, you could set up a config transformation and a custom msbuild target that will create the web.config with local settings and the redirects included. If you're not familiar with how to do this, this is how I generate config files when I need to see how they would look when deployed to the Episerver DXC that uses config transformations:

<Target Name="DXCConfigs">
  <TransformXml Source="web.config" Transform="Web.integration.config" Destination="web.integration.out.dxc.config" />
  <TransformXml Source="web.integration.out.dxc.config" Transform="web.preproduction.config" Destination="web.preproduction.out.dxc.config" />
  <TransformXml Source="web.preproduction.out.dxc.config" Transform="web.production.config" Destination="web.production.out.dxc.config" />
</Target>

and you run it from the command-line like this:

msbuild /T:DXCConfigs

After this is done, you need to make sure you local IIS listens to all domains you are going to test. The easiest way to accomplish this is to just add a wildcard mapping but if this is not possible for you, add them one by one under Edit Bindings in IIS. Note that if the redirect rules include upgrading the connection to https, you need to add a self signed certificate and add mappings in IIS for this too.

Now edit the hosts file and add your hosts

127.0.0.1 episerver.com
127.0.0.1 www.episerver.com
127.0.0.1 ektron.com
127.0.0.1 www.episerver.se

One thing to note is that if you are testing redirects with HTTPS, you need Chromium to ignore SSL certificate warnings for your local certs for the script to work, this is done by launching puppeteer with the ignoreHTTPSErrors flag set to true as can be seen in the script below.

My script looks like this:

/*
Test redirects
*/

const puppeteer = require('puppeteer');

(async () => {

  async function testurl( fromurl, tourl) {
  try {
     await page.goto(fromurl, {
     waitUntil: 'networkidle2'
   });
   if (await page.url() === tourl) {
     await console.log("Success: ", page.url());
     return true;
   } else {
     console.log("*** Fail. " + fromurl + " Got: ", page.url() + " expected: " + tourl);
     return false;
   }
  } catch (error) {
   console.log("*** Error " + fromurl + " " + error);
   }
  }

  // set up puppeteer to ignore HTTPS errors so it won't bomb on your self-signed certificates
  const browser = await puppeteer.launch({
    ignoreHTTPSErrors: true
  });

  const page = await browser.newPage();

  await testurl('http://episerver.se', 'https://www.episerver.se/');
  await testurl('http://ektron.com/', 'https://www.episerver.com/');
  await testurl('https://www.EPiServer.COM/', 'https://www.episerver.com/');
  await testurl('https://www.episerver.com/ascend-conference/ascend-2019', 'https://www.episerver.com/ascend-conference/ascend-2019/');
  await testurl('http://www.episerver.no/dxc', 'https://www.episerver.no/produkter/funksjoner/plattform-som-en-tjeneste/');

  await browser.close();
  })();

I only used my script to manually validate that the rules I introduced didn't break any of the other redirects (it turned out they did), especially the ones I had in the Geta 404 handler, but if you need to do this in a more unittest-like fashion, see this post for inspiration on how to use an assertion framework with Headless Chrome.

Finally, when you are sure you didn't break anything with your new rules and they were deployed into production, just comment out the entries in the hosts file and run the script again to test the rules in production if you'd like to.

Sep 04, 2019

Comments

Sep 5, 2019 01:16 PM

We created a tool for generating IIS rewrite rules from a speadsheet. I recently updated it so when it creates them it creates a full suite of postman tests in a collection which validate the to and from. Used it for validating 50k redirects on a recently project and worked really well

Johan Antila
Johan Antila Sep 6, 2019 09:18 AM

Thanks Scott, that's clever! If anyone is interested in that approach, you can read about it here: https://world.episerver.com/blogs/scott-reed/dates/2019/9/client-driven-rewrite-rules-with-automated-postman-tests/

Daniel Ovaska
Daniel Ovaska Sep 10, 2019 08:34 AM

Ah! Cool. I have to test that! Great work guys

Please login to comment.
Latest blogs
Copy Optimizely SaaS CMS Settings to ENV Format Via Bookmarklet

Do you work with multiple Optimizely SaaS CMS instances? Use a bookmarklet to automatically copy them to your clipboard, ready to paste into your e...

Daniel Isaacs | Dec 22, 2024 | Syndicated blog

Increase timeout for long running SQL queries using SQL addon

Learn how to increase the timeout for long running SQL queries using the SQL addon.

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Overriding the help text for the Name property in Optimizely CMS

I recently received a question about how to override the Help text for the built-in Name property in Optimizely CMS, so I decided to document my...

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Resize Images on the Fly with Optimizely DXP's New CDN Feature

With the latest release, you can now resize images on demand using the Content Delivery Network (CDN). This means no more storing multiple versions...

Satata Satez | Dec 19, 2024