A night of firsts: VS2010, Dynamics, Python

Tonight, I installed Visual Studio 2010 beta 1 for the first time. I know I am late to the game, but I had to give it a whirl since I found some free time this afternoon. One feature of .NET 4.0 I wanted to try out was the dynamic keyword with Python scripting. So, here is my first hello world program using dynamic, with the help of this walk-through.

class HelloWorldDemo:
 
    def run(self):
        return "hello world"

Here is the C# code needed to run it. Yes, I used WPF as my driver, but don’t worry about that.

...
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
 
namespace WpfWithPython
{
    public partial class Window1 : Window
    {
        ScriptRuntime py;
        public Window1()
        {
            InitializeComponent();
            py = Python.CreateRuntime();
        }
 
        private void MyBtn_Click(object sender, RoutedEventArgs e)
        {
            //Instantiate an instance of this file?!  Yes, it is weird at first.  
            // All the methods and classes in the file will be members.
            dynamic demo = py.UseFile("HelloWorldDemo.py");
 
            //This is the tricky step.  To create a new object, call it like a member...
            // I think
            dynamic instance = demo.HelloWorldDemo();
            MyText.Text = instance.run();
        }
    }
}

It took me a while to get this little bit of code working unfortunately. If you read the comments, you can see where some of my confusion was found. Overall, it is pretty awesome. I loved LINQ and I am already loving dynamic. There is something new to learn everyday. Maybe F# next…

Unfortunately, I have to say that VS2010, while pretty, is slower than 2008. And, IronPython took nearly 2 or 3 minutes to run some sample code it provided, which is crazy. If the performance problems can be overcome, then I see myself learning more Python and Ruby.

Why I like WPF, yet dislike Web Forms

I have been playing with WPF over the past few weeks, and I kind of like it. What’s odd is I hate Web Forms, which has very similar concepts to WPF. Concepts like controls, data binding, data templates, etc…

Why do I think WPF works while Web Forms don’t?

The first step is really understanding what I dislike in Web Forms. Two reasons, ViewState and controls.

ViewState

I hate the ViewState. It is a very complex mechanism of changing a stateless medium, HTTP, into a stateful one. While it accomplishes that task, I don’t believe the trade-offs are worth it. Developers must understand how HTTP works, and how the ViewState works. It is not an abstraction that allows ignorance because it leaks all the intricacies of HTTP as well as adding a ton of complexity on top of it.

I think understanding HTTP is stateless and coding your application to work in that medium is much easier than coding your application to be stateful and fixing it to work in a stateless medium.

Controls

Imagine you had a markup language that controls how something is displayed. It is ubiquitous and highly standardized. Now create an abstraction that wraps it, hides the simplicity, and adds ViewState, which I obviously don’t like. That is what controls in Web Forms are.

Let me interject that I don’t hate controls like I hate the ViewState. I actually like some of the principles behind them. The ability to easily reuse HTML is great. The ability to data-bind to objects is awesome.

What I don’t like is the fact that I believe it is an unnecessary abstraction. At the end of the day, all a browser cares about is HTML. And I love HTML and am good at HTML. Why take that away from me? Not to mention things like repeaters are just foreach loops.

Why is WPF different?

Two reasons that you can probably guess.

Desktop apps are stateful. There is no ViewState. There is just memory. And I understand memory.

Controls are the real thing, not an abstraction around the real thing (Yes I understand they are actually an abstraction around something, but it is a good abstraction. One that doesn’t leak like crazy. I can ignore how it works under the hood).

Now WPF isn’t perfect. Unit testing out of the bag isn’t easy, but it is possible. Just like using model-view-presenter is possible in web forms.

Using Pipeline.Input for Powershell testing

Last week, I posted about how to unit test powershell, which I have been working with a little bit over the weekend. One thing I quickly realized was testing interaction with the pipeline is a must for Powershell. It’s pretty easy to do.

Let’s start with the Get-Service cmdlet that ships with Powershell. If you load up reflector, you will see the follow class definition.

[Cmdlet("Get", "Service", DefaultParameterSetName="Default")]
public sealed class GetServiceCommand : MultipleServiceCommandBase
{
    // Methods
    public GetServiceCommand();
    protected override void ProcessRecord();
 
    // Properties
    [Parameter(Position=0, 
          ParameterSetName="Default", 
          ValueFromPipelineByPropertyName=true, 
          ValueFromPipeline=true),
     Alias(new string[] { "ServiceName" })]
    public string[] Name { get; set; }
}

Remembering the base test fixture from the previous post on TDD in Powershell, I can quickly write up a few tests that test a few different use cases of the get-service cmdlet with

 
[Test]
public void Get_Service_with_single_string_in_pipeline() 
{
    // "MySQL" | get-service
 
    var name = "MySQL";
 
    var pipeline = Runspace.CreatePipeline();
 
    pipeline.Input.Write(name);
    pipeline.Commands.Add("get-service");
 
    var result = pipeline.Invoke();
 
    AssertThatPipelineResultIsService(result, name);
}
 
[Test]
public void Get_Service_with_single_object_in_pipeline_using_Name_property()
{
    //New-Object PSObject | Add-Member NoteProperty Name "MySQL" -PassThru | get-service
 
    var name = "MySQL";
 
    var pipeline = Runspace.CreatePipeline();
 
    pipeline.Input.Write(new { Name = name });
    pipeline.Commands.Add("get-service");
 
    var result = pipeline.Invoke();
 
    AssertThatPipelineResultIsService(result, name);
}
 
[Test]
public void Get_Service_with_single_object_in_pipeline_using_ServiceName_property()
{
    //New-Object PSObject | Add-Member NoteProperty ServiceName "MySQL" -PassThru | get-service
 
    var name = "MySQL";
 
    var pipeline = Runspace.CreatePipeline();
 
    pipeline.Input.Write(new { ServiceName = name });
    pipeline.Commands.Add("get-service");
 
    var result = pipeline.Invoke();
 
    AssertThatPipelineResultIsService(result, name);
}
 
private void AssertThatPipelineResultIsService(Collection<PSObject> result, string name)
{
    Assert.That(result.Count == 1);
    Assert.That(result[0].BaseObject is ServiceController);
    Assert.That((result[0].BaseObject as ServiceController).ServiceName == name);
}

By using pipeline.Input.Write(), I can write to the pipeline before invoking commands. Really easy to do, and super useful, because each Powershell cmdlet can probably be called a bunch of different ways.

Where can you use it? Snap in development or testing your own Powershell scripts. Stop guessing how the pipeline is going to work and test it.

TDD with Powershell, from the client perspective

Is it possible? Yes, and it is actually relatively easy. The hardest part can be figuring out how to mock/stub out certain functionality so your testing small units as opposed to full acceptance testing. The line can get blurry, but I don’t really care. Testing is half the battle.

But to be clear, the focus of my testing is to test how a snap-in is working. It sounds like an integration test, and maybe it is, but there is no reason you couldn’t test any powershell script using some of the steps outlined here. Just be flexible and creative.

Start by creating a nice base test fixture.

public abstract class PowershellTestFixture
{
    protected Runspace Runspace { get; set; }
 
    public void CreateRunspace()
    {
        Runspace = RunspaceFactory.CreateRunspace(CreateConfiguration());
        Runspace.Open();           
    }
 
    public void CloseRunspace()
    {
        Runspace.Close();
        Runspace.Dispose();
    }
 
    private RunspaceConfiguration CreateConfiguration()
    {
        var config = RunspaceConfiguration.Create();
 
        PSSnapInException warning;
        config.AddPSSnapIn("SomeCustomSnapIn", out warning);
 
        return config;
    }
 
    protected Collection<PSObject> ExecutePowershell(string script)
    {
        return Runspace.CreatePipeline(script).Invoke();
    }
}

In this base class, I just created some nice helper methods, and one method that samples how to add a snap-in to the runspace.

Now, just write a test, and add your assertions. And it will work!

[TestFixture]
public class TestSomethingStupid : PowershellTestFixture
{
    [SetUp]
    public void Setup()
    {
        CreateRunspace();
    }
 
    [TearDown]
    public void TearDown()
    {
        CloseRunspace();
    }
 
    [Test]
    public void GetServiceWhereNameIsMySql()
    {
        string cmd = @"
get-service | where { $_.name -eq 'MySQL' }
";
        var result = ExecutePowershell(cmd)
            .Select(o => o.BaseObject)
            .Cast<System.ServiceProcess.ServiceController>()
            .First();
 
        Assert.AreEqual(result.ServiceName, "MySQL");            
    }
}

Obviously this test is stupid. But that’s not the point. In a very few lines, I have tested the output of some powershell. Pretty cool if you ask me, especially if your coding a snap in. If you aren’t automating the tests, how else can you verify it works except to recompile, install, open powershell, and type some code? Very slow and painful!

It is important to note, there are other ways to test snap-in’s. What I really wanted to see is how my cmdlet’s looked from the powershell perspective, not the C# perspective.

DateTime.ParseExact()

Today I used this function for the first time. Somehow, I have never needed this before. It is super simple and very useful though. It is basically the inverse of DateTime.ToString(“yyyy-mm-dd”). It allows you to parse a custom date/time format.

So, for example a Pound proxy log has a date in the format 12/Mar/2009:05:00:36 -0400, which isn’t a standard format in .NET. Using ParseExact, parsing it was a piece of cake.

$provider = New-Object System.Globalization.CultureInfo "en-US"
[DateTime]::ParseExact($line.date, "dd/MMM/yyyy:hh:mm:ss zz00", $provider)