Testing .NET Core RC2 Using NUnit 3

Things have changed since I wrote Testing .NET Core Using NUnit 3, so it is time to update the steps for .NET Core RC2.

The code from this post is on GitHub.

Upgrading your project to build on RC2 is a whole series of blog posts in and of itself, so I won’t cover it here, but I will remind everyone, “All previous versions of .NET Core and any tooling must be removed from the machine in order to properly install and use RC2 release.” I uninstalled everything, deleted all directories in Program Files that had DNX or DotNet in their name, deleted the .dnx directory in my user directory and combed through my user and global paths before installing .NET Core RC2. I didn’t get everything on one machine and was getting strange errors.

So, let’s go green field, in Visual Studio, File | New | Project… and select Class Library (.NET Core) under the new C# | .NET Core node.

New .NET Core Project

This it the code under test. To this, I have added the simple calculator class from the last post.

public static class Calculator
{
    public static int Add(int x, int y) => x + y;
    public static int Subtract(int x, int y) => x - y;
    public static int Multiply(int x, int y) => x * y;
    public static int Divide(int x, int y) => x / y;
}

If you look in global.json, the new standard is to put your code in src and tests in test directories. To conform with this, add a New Solution Folder named test.

{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-preview1-002702"
  }
}

To this new test folder, add a new Console Application (.NET Core) as your test project and add a reference to the main project.

Add New Console Project

Now, add the NUnitLite NuGet package to the test project and change Main in Program.cs.

using NUnit.Common;
using NUnitLite;
using System;
using System.Reflection;

namespace NUnitWithDotNetCoreRC2.Test
{
    public class Program
    {
        public static int Main(string[] args)
        {
            return new AutoRun(typeof(Program).GetTypeInfo().Assembly)
                .Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
        }
    }
}

You can now add your tests to the project.

using NUnit.Framework;

namespace NUnitWithDotNetCoreRC2.Test
{
    [TestFixture]
    public class CalculatorTests
    {
        [TestCase(1, 1, 2)]
        [TestCase(-1, -1, -2)]
        [TestCase(100, 5, 105)]
        public void CanAddNumbers(int x, int y, int expected)
        {
            Assert.That(Calculator.Add(x, y), Is.EqualTo(expected));
        }

        [TestCase(1, 1, 0)]
        [TestCase(-1, -1, 0)]
        [TestCase(100, 5, 95)]
        public void CanSubtract(int x, int y, int expected)
        {
            Assert.That(Calculator.Subtract(x, y), Is.EqualTo(expected));
        }

        [TestCase(1, 1, 1)]
        [TestCase(-1, -1, 1)]
        [TestCase(100, 5, 500)]
        public void CanMultiply(int x, int y, int expected)
        {
            Assert.That(Calculator.Multiply(x, y), Is.EqualTo(expected));
        }

        [TestCase(1, 1, 1)]
        [TestCase(-1, -1, 1)]
        [TestCase(100, 5, 20)]
        public void CanDivide(int x, int y, int expected)
        {
            Assert.That(Calculator.Divide(x, y), Is.EqualTo(expected));
        }
    }
}

You can now set the test project as your startup project and run your tests. If it helps, put a breakpoint in Main to see the output.

NUnitLite 3.2.1 (Portable)
Copyright (C) 2016 Charlie Poole

Test Files
    D:\Src\Spikes\NUnitWithDotNetCoreRC2\NUnitWithDotNetCoreRC2.Test\bin\Debug\netcoreapp1.0\NUnitWithDotNetCoreRC2.Test.dll

Run Settings
    Internal Trace: Off

Test Run Summary
  Overall result: Passed
  Test Count: 12, Passed: 12, Failed: 0, Inconclusive: 0, Skipped: 0
  Start time: 2016-05-18 14:47:56Z
    End time: 2016-05-18 14:47:56Z
    Duration: 0.070 seconds

All in all, for a green field app, then it is pretty straight forward. If you prefer that your tests are in a DLL, then you can follow the steps above, but possibly name the NUnitLite project as a runner and change the AutoRun to get the assembly from a class in your test project. If you prefer this method, I have done it in the test_assembly branch on GitHub.

I am in the process of upgrading a few RC1 projects, so if I find any other gotchas, I will update. For upgrades, one thing you will have to do is add an imports statement to your project.json to handle the renaming of the targets in RC2. This is done for you if you create a new project, but not if you are upgrading.

For project.json in a console runner;

  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }

Or in an assembly;

  "frameworks": {
    "netstandard1.5": {
      "imports": "dnxcore50"
    }

Read more

Arduino based Build Indicator

Arduino based build indicatorI found a red strobe light in the bargain bin at a local electronics store and immediately knew what to do with it – create a build failed light. There is a long history of dev shops creating build indicator lights using lava lamps, stop lights and computer monitors mounted on the wall and I’ve always wanted to build one.

The strobe was rated at 12V, but I wanted to run it off USB, so I hooked it up to a 5V power supply. It strobed a bit slower, but it worked, so I checked the amps. It drew a steady 70mA which is too much to run directly off an Arduino pin which are limited to around 40mA, but still low enough to run off USB and the 5V pin on the Arduino. I could use a relay to switch the strobe, but it seemed like overkill, so I checked my parts drawer and found some PN2222A transistors which are rated to 40V and 800mA.

Software

Since I was going to power this project off USB, I decided to let the computer do the heavy lifting of checking the state of the build and signal the Arduino over serial. The Arduino code is pretty simple, listen on serial, if it receives a 0, set pin 13 LOW, if it receives a 1, set pin 13 HIGH.

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize serial:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  // prints title with ending line break
  Serial.println("Alert Ready. Enter 1=ON 0=OFF");
  
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  if(Serial.available())
  {
    char input = Serial.read();
    if(input == '0'){
      digitalWrite(13, LOW);
      Serial.println("Turning OFF alert");
    }
    else if(input == '1') {
      digitalWrite(13, HIGH);
      Serial.println("Turning ON alert");
    }
    else {
      Serial.println("Unrecognized command.  Enter 1=ON 0=OFF");
    }
  }
}

On the computer, I wrote a simple Python script to get the RSS feed for our CruiseControl.NET build results. RSS doesn’t contain build specific nodes, so I just search for the word Success in the RSS title. The python script just loops, looks for new RSS items and sends a 0 or 1 to the Arduino over serial. It should be fairly simple to change the script to work with your build server.

#! python3

import feedparser
import serial
import time

COM_PORT  = 'COM6'
BAUD_RATE = 9600
FEED_URI  = 'http://ccbuild/ccnet/server/local/project/OurProductBuild/RSSFeed.aspx'
CHECK_FREQUENCY = 60    # How often to check in seconds

def printTitle(title):    
    print('===================')
    print('  ' + title)
    print('===================')
    print()

id = '' # Track the last RSS entry we found
port = serial.Serial(COM_PORT, BAUD_RATE)
print(port.readline().decode())

while True:
    # get the feed data from the url
    feed = feedparser.parse(FEED_URI)

    # display info for the first post
    num = len(feed.entries)
    success = False
    if num > 0:
        entry = feed.entries[num-1]

        # Have we already seen this entry?
        if id == entry.id:
            time.sleep(CHECK_FREQUENCY)
            continue

        id = entry.id
        printTitle('New build found')
        print(entry.title)
        print()
        success = 'Success' in entry.title
    else:
        printTitle('No build found')

    # Switch the Arduino alert on/off
    if success:
        print('Build succeeded')
        port.write(b'0')
    else:
        print('Build failed')
        port.write(b'1')
    
    print(port.readline().decode())
    time.sleep(CHECK_FREQUENCY)

Hardware

I started by prototyping on a breadboard using a red LED to stand in for the strobe. The green LED is a power indicator. Once I knew the code and the hardware was working, I then added the strobe in parallel to the LED and its resistor.

Strobe Breadboard

I then soldered the components for the transistor switching circuit onto a small prototyping board.

Transistor switching circuit

Then wired the board to an old Arduino Uno, put it in a small box and screwed the strobe to the box.

Project box

And then put the strobe up at work. Sorry, I couldn’t catch the flashing…

Build indicator strobe

Read more

Restore a SQL Server Backup to LocalDb

I’m experimenting with taking a 3-tier client/server/database application and creating a lightweight client application that uses an embedded database. We use stored procedures and our server application uses SQL Server, so SQL Express LocalDB has potential. The only problem I ran into was restoring a backup taken from SQL Server to LocalDB and it appears that I am not the only one that had problems.

In the end though, it was pretty easy, it just required a few steps that most DB admins are already familiar with, but developers may stumble on. Here are the developer-centric instructions using Visual Studio.

In Visual Studio, open SQL Server Object Explorer (Ctrl+\, Ctrl+S) or under the View menu. Open the SQL Server node and you will likely have several LocalDB instances. If not, click the Add SQL Server button and from the dropdown, select (localdb)\MSSQLLocalDB.

Open the node for the version of LocalDB you want to use and expand Databases | System Databases. Right click on master and select New Query…

New Query

Execute the following query using the path to your database backup.

RESTORE FILELISTONLY
FROM DISK = 'D:\tmp\ivaraapplicationtesting75.bak'

In the results, take note of the LogicalName.

LogicalName

Modify your query to do the restore, using your database name, backup and the LogicalName from the previous query. You can restore the database to any existing path, in this case, I am restoring to my home directory.

RESTORE DATABASE IvaraApplicationTesting
FROM DISK = 'D:\tmp\ivaraapplicationtesting75.bak'

WITH MOVE 'ivara_data' TO 'C:\Users\rob.prouse\IvaraApplicationTesting.mdf',
MOVE 'ivara_log' TO 'C:\Users\rob.prouse\IvaraApplicationTesting.ldf',
REPLACE;

First time I did this, I thought it didn’t work because it happened so quickly and because the database did not show up in SQL Server Object Explorer, but all you need to do is click refresh.

Results

If you expand your new database, you will see that all of your tables are there and you can execute queries against it.

Read more

Install Docker on Windows in Hyper-V

Containers are the future, so I need to be able to work with Docker. On Windows, Docker runs inside a virtual machine and by default ships with VirtualBox. As a Windows developer, all of my virtual machines and emulators are Hyper-V images which conflicts with VirtualBox. In the past, I would dual boot to switch between Hyper-V and VirtualBox, but that is a huge pain, so I decided to figure out how to get Docker running in Hyper-V. It turns out that it isn’t difficult, but most of the instructions assume VirtualBox or are out of date.

Install Docker

We’re all Windows developers here, so I will assume that you are already using Hyper-V and that it is working.

Download Docker Toolbox for Windows

Run the installer. On the third screen, you cannot uncheck VirtualBox even though you don’t need it. Damn you Docker! No worries, we can get around that…
Setup - Docker Toolbox

On the fourth screen, select all options, then continue to click through all of the screens.

At the end of the Docker Toolbox install, it will begin installing VirtualBox. A Windows Security dialog will pop up asking you if you want to install Oracle device software. Clicking Don’t Install will abort the VirtualBox install.
Windows Security

The Docker Quickstart Terminal and Kitematic (Alpha) shortcuts won’t work without VirtualBox, so skip them. We will install the Docker vm into Hyper-V manually.

Create a Boot2Docker Hyper-V Machine

If you have many virtual machines in Hyper-V, you will likely have several Virtual Switches. You must specify which Virtual Switch to use when you create the Docker VM, so open Hyper-V Manager and select Virtual Switch Manager from the actions on the right.

Select a Virtual Switch that is connected directly to an external network interface, ideally to an ethernet connection, not to a wireless card. Copy the name of the switch, you will use it when you create the virtual machine.

Hyper-V Virtual Switch

Open an Admin command prompt and run docker-machine create, substituting your  virtual switch name. In this example, the Hyper-V machine will be called Boot2Docker. See the Docker Hyper-V documentation for more command line options.

D:\src
Ω docker-machine create --driver hyperv --hyperv-virtual-switch "Intel(R) Ethernet Connection I217-LM Virtual Switch" Boot2Docker
Creating CA: C:\Users\rob.prouse\.docker\machine\certs\ca.pem
Creating client certificate: C:\Users\rob.prouse\.docker\machine\certs\cert.pem
Running pre-create checks...
Creating machine...
(Boot2Docker) Copying C:\Users\rob.prouse\.docker\machine\cache\boot2docker.iso to C:\Users\rob.prouse\.docker\machine\machines\Boot2Docker\boot2docker.iso...
(Boot2Docker) Creating SSH key...
(Boot2Docker) Creating VM...
(Boot2Docker) Using switch "Intel(R) Ethernet Connection I217-LM Virtual Switch"
(Boot2Docker) Creating VHD
(Boot2Docker) Starting VM...
(Boot2Docker) Waiting for host to start...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: C:\Program Files\Docker Toolbox\docker-machine.exe env Boot2Docker

As this is working, back in Hyper-V Manager, connect to your docker image to see what it is doing.

Boot2Docker

I don’t like working as an admin if I don’t need to, so close your admin command prompt and open a regular command prompt for the remaining work.

That’s it, you now have Docker installed and running in Hyper-V. Next up, let’s configure the Docker client to connect to your vm.

Working with docker-machine

From this point on, everything is standard Docker commands, so check out the docker-machine documentation. Whenever you want to work with Docker, you use docker-machine to start and stop your machines, to list running machines and to configure your shell to connect to a running Docker instance.

Listing Docker Machines

You use docker-machine ls to view registered Docker machines and their state.

D:\src
λ docker-machine ls
NAME          ACTIVE   DRIVER   STATE     URL                        SWARM   DOCKER    ERRORS
Boot2Docker   -        hyperv   Running   tcp://192.168.0.113:2376           v1.10.2

Starting and Stopping Machines

Use docker-machine start [MachineName] and docker-machine stop [MachineName] to start and stop virtual machines.

λ docker-machine start Boot2Docker
Starting "Boot2Docker"...
(Boot2Docker) Waiting for host to start...
Machine "Boot2Docker" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

Configuring Your Shell

To connect your Docker client to a running vm, use the command docker-machine env [MachineName].

D:\src
λ docker-machine env Boot2Docker
$Env:DOCKER_TLS_VERIFY = "1"
$Env:DOCKER_HOST = "tcp://192.168.0.113:2376"
$Env:DOCKER_CERT_PATH = "C:\Users\rob.prouse\.docker\machine\machines\Boot2Docker"
$Env:DOCKER_MACHINE_NAME = "Boot2Docker"
# Run this command to configure your shell:
# & "C:\Program Files\Docker Toolbox\docker-machine.exe" env Boot2Docker | Invoke-Expression

The last line tells you what you need to run to configure your shell. I am using PowerShell, so I need to run & docker-machine env Boot2Docker | Invoke-Expression to set the required environment variables.

Test Your Docker Installation

Now that you are setup and have your shell configured, run docker run hello-world to check that everything is working.

D:\src
λ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world

03f4658f8b78: Pull complete ================================================>]    601 B/601 BB
a3ed95caeb02: Pull complete ================================================>]     32 B/32 BB
Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
Status: Downloaded newer image for hello-world:latest

Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/userguide/

From here, if you are new to Docker, I would suggest continuing with the Docker on Windows Getting Started Step 2 – Understanding images & containers which picks up from this point.

Read more

Automate Shutting Down Azure VMs

As I am developing, I create and use quite a few Microsoft Azure services and virtual machines. If I forget to shut down the services at the end of the day, it will quickly burn through my MSDN Azure credits leaving me dead in the water until the end of the month.

This happened to me last month and I vowed never again, so I dove into Azure Automation Accounts to automatically shut down services at the end of the day. The setup wasn’t intuitive, but it can be really useful for cleaning up, or any scheduled maintainance of your account. Just make sure you don’t end up taking down production services by mistake!

Create an Azure Active Directory Account

If like me you use multi-factor authentication for your Azure account, you cannot use your account to run automation scripts. Instead, you will need to create an Azure Active Directory account to run the automation scripts. If you are not using multi-factor authentication, you should consider switching, but if not, you can skip this and use your own account when setting up the credentials in the automation account below.

You need to log into the Azure Portal using the account of the Service Administrator to add new users. If this is your MSDN Subscription, you are likely the Service Administrator, but if it is a company account, you can find the Service Administrator by logging in with your account, then going to Subscriptions. Click on the subscription you want to administer, then All Settings | Properties.

Subscription Admin

The bottom text box in the Properties blade is the Service Admin, log in with that account and click on Active Directory. This currently launches you into the classic portal.

On the left, click on the Directory for the subscription, then on the USERS tab. If you do not see the directory listed, you are not the admin for the directory. Now click on Add User at the bottom.

Azure Active Directory

Select “New user in your organization” and enter a username for your automation user.

New AD User

Click next and fill in the user information. The role should be User and don’t enable multi-factor authentication.

New AD User Step 2

Click next, then Create to create the user and generate a temporary password for the user. Write down the username and the temporary password.

Since this is a temporary password, you must change it. Do this by logging out of Azure and logging back in with the newly created automation account. It will prompt you to change the password, do so, then log out and back in with your account.

Allow the Automation User to Manage your Subscription

Log back into the Classic Azure Portal with your user, click Settings at the bottom left, then Administrators.

Subscription Admins

Enter the email for the user you just created and select the subscription they will manage.

CoAdministrator

Create an Automation Account

Back in the Azure Portal using your MSDN Subscription account, click on Automation Accounts. On the Automation Accounts blade, click on Add.

Create Automation Account

Give the new account a recognizable name. You will probably want to assign it to the same resource group as the services you are managing and select the same region. The default account options creates a tutorial runbook, leave it on, the code is useful to crib off of. When you are ready, click Create. After it is deployed, you will have a new automation account. Drill into it.

Automation Account

Add Credentials to the Account

Automation scripts need credentials to run under, so the first step is to add them. Click on the Assets tile, then the Credentials tile then Add a Credential.

New Automation Credentials

If you name the credentials DefaultAzureCredential then you you do not need to change the example automation scripts. If you prefer to use another name, you will need to change it in the automation scripts. For the username and password, use the automation user you created at the start of this post. If you skipped that and don’t use multi-factor authentication I believe you can use your MSDN account.

Testing Your Setup

Close back out to the blade for your automation account and click on Runbooks. You should have a single Get-AzureVMTutorial runbook that was created when you created the account. We’ll use this to test that you have the credentials setup correctly. Click on the runbook to open its blade. If you used DefaultAzureCredential for the credentials name, you can just press Start. If you used a different name, edit the script and change the authentication account where specified.

A job blade will open and the job will cycle through Queued, Starting, Running and if all goes well Completed. If it fails for some reason, then the an exception will be shown at the bottom of the blade and the job will become Suspended. If it does this, stop it. If it succeeded, click the output tile to see the list of classic VMs that it found in your subscription.

Test Run

Time to write some code

If you peeked at the tutorial runbook code, you will see that it is just a PowerShell script. Time to create our own. I like to test what I am writing in the PowerShell ISE on my machine, but I will leave the setup of that to another blog post. For now, let’s create a simple runbook to shutdown virtual machines.

Back on the blade for your automation account, click Runbooks and Add a runbook.

Add Runbook - Microsoft Azure

Create a new runbook called Stop-AzureVirtualMachines of type PowerShell Workflow and give it a meaningful description and click Create.

Runbook - Microsoft Azure

A new Workflow Runbook will open in the editor, copy the following code in;

<#
  .DESCRIPTION
    Stops all Azure Virtual Machines in an account. To stop classic VMs, change Get-AzureRmVM and Stop-AzureRmVM to
    Get-AzureVM and Stop-AzureVM

  .NOTES
    AUTHOR: Rob Prouse
    LASTEDIT: Feb 08, 2016
#>
workflow Stop-AzureVirtualMachines
{
  #The name of the Automation Credential Asset this runbook will use to authenticate to Azure.
  $CredentialAssetName = 'DefaultAzureCredential'

  #Get the credential with the above name from the Automation Asset store
  $Cred = Get-AutomationPSCredential -Name $CredentialAssetName
  if(!$Cred) {
    Throw "Could not find an Automation Credential Asset named '${CredentialAssetName}'. Make sure you have created one in this Automation Account."
  }

  #Connect to your Azure Account
  $Account = Add-AzureRmAccount -Credential $Cred
  if(!$Account) {
    Throw "Could not authenticate to Azure using the credential asset '${CredentialAssetName}'. Make sure the user name and password are correct."
  }

  #TODO (optional): pick the right subscription to use. Without this line, the default subscription for your Azure Account will be used.
  #Select-AzureRmSubscription -SubscriptionName "TODO: your Azure subscription name here"
  
  #Get all the VMs you have in your Azure subscription
  $VMs = Get-AzureRmVM

  # Stop each of the started VMs
  foreach ($VM in $VMs)
  {      
      Write-Output ("Stoping " + $VM.Name)
      Stop-AzureRmVM -Name $VM.Name -Id $VM.Id -Force -ErrorAction Continue
  }
}

If you didn’t use DefaultAzureCredential when you created the credentials, make sure you change it in the script. Also, if you have more than one subscription, uncomment the Select-AzureRmSubscription line. Notice that this script shuts down the new Azure Virtual Machines using the PowerShell commands with Rm in them like Get-AzureRmVM. If you want to shut down classic VMs or other services, modify accordingly.

You can now test your script by clicking the Test pane button and starting your script. If you see any errors, make the necessary edits to get it running in your account. Once it is running, exit the test blade and click Publish.

After you publish the script, the edit blade should close. Back in the runbook blade, double check that the status is Published.

2016-02-08 15_37_25-Stop-AzureVirtualMachines - Microsoft Azure

Scheduling the Job

Last step, promise. In the blade for the runbook you just created, click the Schedules tile, Add a schedule, Schedule and Create a new schedule. Give it a name like Every Evening at 6pm, a description, a start date and time in the future and a daily recurrence. You can now exit out of the blades, you are done.

New Schedule

Monitoring your Jobs

Optionally, you may want to monitor the status of your jobs to make sure they don’t start failing. Do do this, go to the blade for your automation account. There is a Job Statistics tile on that blade. Right click on it and pin it to your dashboard for easy viewing…

Job Statistics

Read more