But it works on my PC!

The random thoughts of Richard Fennell on technology and software development

When your TFS Lab test agents can’t start check the DNS

Lab Management has a lot of moving parts, especially if you are using SCVMM based environments. All the parts have to communicate if the system is work.

One of the most common problem I have seen are due to DNS issues. A slowly propagating DNS can cause chaos as the test controller will not be able to resolve the name of the dynamically registered lab VMs.

The best fix is to sort out your DNS issues, but that is not always possible (some things just take the time they take, especially on large WANs).

An immediate fix is to use the local host files on the test controller to define IP address for the lab[guid].corp.domain names created when using network isolation. Once this is done the handshake between the controller and agent is usually possible.

If it isn’t then you are back to all the usually diagnostics tools

More on TF215106: Access denied from the TFS API after upgrade from 2012 to 2013

In my previous post I thought I had fixed my problems with TF215106 errors

"TF215106: Access denied. TYPHOONTFS\\TFSService needs Update build information permissions for build definition ClassLibrary1.Main.Manual in team project Scrum to perform the action. For more information, contact the Team Foundation Server administrator."}

Turns out I had not, acutally I not idea why it worked for a while! There could well be an API version issue, but I had to actually also missed I needed to do what the error message said!

If you check MSDN, it tells you how to check the permissions for a given build; on checking I saw that the update build information permission was not set for the build in question.

image

Once I set it for the domain account my service was running as, everything worked as expected.

All I can assume that there is a change from TSF 2012 to 2013 over defaulting the permission as I have not needed to set it explicitly in the past

Changes in Skydrive access on Windows 8.1

After upgrading to Windows 8.1 on my Media Center PC I have noticed a change in SkyDrive. The ‘upgrade’ process from 8 to 8.1 is really a reinstall of the OS and reapplication of Windows 8 applications. Some Windows desktop applications are removed. In the case of my Media Center PC the only desktop app installed was Windows Desktop Skydrive that I used to sync photos from my MediaPC to the cloud. This is no longer needed as Windows 8.1 exposes the Skydrive files linked to the logged in LiveID as folders under the c:\user\[userid]\documents folder, just like Windows Desktop client used to do.

This means though the old dekstop Skydrive client has been removed my existing timer based jobs that backup files to the cloud by copying from a RAID5 box to the local Skydrive folder still work.

A word of warning here though, don’t rely on this model as you only backup. There is a lot of ransonware around at the moment and if you aren't careful an infected PC can infect your automated cloud backup too. Make your you cloud backup is versioned so you can old back to a pre-infected file and/or you have a more traditional offline backup too.

Can I use the HP ALM Synchronizer with TF Service?

I recently tried to get the free HP ALM Synchronizer to link to Microsoft’s TF Service, the summary is it does not work. However, it took me a while to realise this.

The HP ALM Synchronizer was designed for TFS 2008/2010 so the first issue you hit is that TF Services is today basically TFS 2013 (and is a moving goal post as it is updated so often). This means when you try to configure the TFS connection in HP ALM Synchronizer  it fails because it cannot see any TFS client it supports. This is fairly simple to address, just install Visual Studio Team Explorer 2010 and patch it up to date so that it can connect to TF Service (you could go back to the 2008 and achieve the same if you really needed to)

Once you have a suitably old client you can progress to the point that it asks you for your TFS login credentials. HP ALM Synchronizer validates they are in the form DOMAIN\USER, this is a problem.

On TF Service you usually login with a LiveID, this is a non-starter in this case. However, you can configure alternative credentials, but these are in the form USER and PASSWORD. The string pattern verification on the credentials entry form in  HP ALM Synchronizer does not accept them, it must have a domain and slash. I could not find any pattern at satisfies both TF Service and the HP ALM Synchronizer setup tool. So basically you are stuck.

So for my client we ended up moving to a TFS 2013 Basic Install on premises and at all worked fine, they could sync HP QC defects into TFS using the HP ALM Synchronizer, so they were happy.

However, is there a better solution? One might be to a commercial product such as Tasktop Sync, this is designed to provide synchronisation services between a whole range of ALM like products. I need to find out if that supports TF Service as yet?

Problems with Microsoft Fake Stubs and IronPython

I have been changing the mocking framework used on a project I am planning to open source. Previously it had been using Typemock to mock out items in the TFS API. This had been working well but used features of the toolset that are only available on the licensed product (not the free version). As I don’t like to publish tests people cannot run I thought it best to swap to Microsoft Fakes as there is a better chance any user will have a version of Visual Studio that provides this toolset.

Most of the changes were straightforward but I hit a problem when I tried to run a test that returned a TFS IBuildDetails object for use inside an IronPython DSL.

My working Typemock based test was as follows

[Test]
     public void Can_use_Dsl_to_get_build_details()
     {
        // arrange
         var consoleOut = Helpers.Logging.RedirectConsoleOut();

         var tfsProvider = Isolate.Fake.Instance<ITfsProvider>();
         var emailProvider = Isolate.Fake.Instance<IEmailProvider>();
         var build = Isolate.Fake.Instance<IBuildDetail>();

         var testUri = new Uri("vstfs:///Build/Build/123");
         Isolate.WhenCalled(() => build.Uri).WillReturn(testUri);
         Isolate.WhenCalled(() => build.Quality).WillReturn("Test Quality");
         Isolate.WhenCalled(() => tfsProvider.GetBuildDetails(null)).WillReturn(build);

         // act
         TFSEventsProcessor.Dsl.DslProcessor.RunScript(@"dsl\tfs\loadbuild.py", tfsProvider, emailProvider);

        // assert
         Assert.AreEqual("Build 'vstfs:///Build/Build/123' has the quality 'Test Quality'" + Environment.NewLine, consoleOut.ToString());
     }

Swapping to Fakes I got

[Test]
     public void Can_use_Dsl_to_get_build_details()
     {
        // arrange
         var consoleOut = Helpers.Logging.RedirectConsoleOut();
         var testUri = new Uri("vstfs:///Build/Build/123");

         var emailProvider = new Providers.Fakes.StubIEmailProvider();
         var build = new StubIBuildDetail()
                         {
                             UriGet = () => testUri,
                             QualityGet = () => "Test Quality",
                         };
         var tfsProvider = new Providers.Fakes.StubITfsProvider()
         {
             GetBuildDetailsUri = (uri) => (IBuildDetail)build
         };

         // act
         TFSEventsProcessor.Dsl.DslProcessor.RunScript(@"dsl\tfs\loadbuild.py", tfsProvider, emailProvider);
     

        // assert
         Assert.AreEqual("Build 'vstfs:///Build/Build/123' has the quality 'Test Quality'" + Environment.NewLine, consoleOut.ToString());
     }

But this gave me the error

Test Name:    Can_use_Dsl_to_get_build_details
Test FullName:    TFSEventsProcessor.Tests.Dsl.DslTfsProcessingTests.Can_use_Dsl_to_get_build_details
Test Source:    c:\Projects\tfs2012\TFS\TFSEventsProcessor\Main\Src\WorkItemEventProcessor.Tests\Dsl\DslTfsProcessingTests.cs : line 121
Test Outcome:    Failed
Test Duration:    0:00:01.619

Result Message:    System.MissingMemberException : 'StubIBuildDetail' object has no attribute 'Uri'
Result StackTrace:   
at IronPython.Runtime.Binding.PythonGetMemberBinder.FastErrorGet`1.GetError(CallSite site, TSelfType target, CodeContext context)
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
at IronPython.Compiler.PythonScriptCode.Run(Scope scope)
at IronPython.Compiler.RuntimeScriptCode.InvokeTarget(Scope scope)
at IronPython.Compiler.RuntimeScriptCode.Run(Scope scope)
at Microsoft.Scripting.SourceUnit.Execute(Scope scope, ErrorSink errorSink)
at Microsoft.Scripting.SourceUnit.Execute(Scope scope)
at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope)
at TFSEventsProcessor.Dsl.DslProcessor.RunScript(String scriptname, Dictionary`2 args, ITfsProvider iTfsProvider, IEmailProvider iEmailProvider) in c:\Projects\tfs2012\TFS\TFSEventsProcessor\Main\Src\WorkItemEventProcessor\Dsl\DslProcessor.cs:line 78
at TFSEventsProcessor.Dsl.DslProcessor.RunScript(String scriptname, ITfsProvider iTfsProvider, IEmailProvider iEmailProvider) in c:\Projects\tfs2012\TFS\TFSEventsProcessor\Main\Src\WorkItemEventProcessor\Dsl\DslProcessor.cs:line 31
at TFSEventsProcessor.Tests.Dsl.DslTfsProcessingTests.Can_use_Dsl_to_get_build_details() in c:\Projects\tfs2012\TFS\TFSEventsProcessor\Main\Src\WorkItemEventProcessor.Tests\Dsl\DslTfsProcessingTests.cs:line 141

If I altered my test to not use my IronPython DSL but call the C# DSL Library directly the error went away. So the issue lay in the dynamic IronPython engine – not something I am going to even think of trying to fix.

So I swapped the definition of the mock IBuildDetails to use Moq (could have used the free version of Typemock or any framework) instead of a Microsoft Fake Stubs and the problem went away.

So I had

[Test]
     public void Can_use_Dsl_to_get_build_details()
     {
         // arrange
         var consoleOut = Helpers.Logging.RedirectConsoleOut();
         var testUri = new Uri("vstfs:///Build/Build/123");

         var emailProvider = new Providers.Fakes.StubIEmailProvider();
         var build = new Moq.Mock<IBuildDetail>();
         build.Setup(b => b.Uri).Returns(testUri);
         build.Setup(b => b.Quality).Returns("Test Quality");

         var tfsProvider = new Providers.Fakes.StubITfsProvider()
         {
             GetBuildDetailsUri = (uri) => build.Object
         };

        // act
         TFSEventsProcessor.Dsl.DslProcessor.RunScript(@"dsl\tfs\loadbuild.py", tfsProvider, emailProvider);


         // assert
         Assert.AreEqual("Build 'vstfs:///Build/Build/123' has the quality 'Test Quality'" + Environment.NewLine, consoleOut.ToString());
     }

So I have a working solution, but it is a bit of a bit of a mess, I am using Fake Stubs and Moq in the same test. There is no good reason not to swap all the mocking of interfaces to Moq. So going forward on this project I only use Microsoft Fakes for Shims to mock out items such as  TFS WorkItem objects which have no public constructor.

Get rid of that that zombie build

Whilst upgrading a TFS 2010 server to 2012 I had a problem that a build was showing in the queue as active after the upgrade. This build was queued in January, 10 months ago, so should have finished a long long time ago. This build had the effect that it blocked any newly queued builds, but the old build did not appear to be running on any agent – a zombie build.

I tried to stop it, delete it, everything I could think of, all to no effect. It would not go away.

In the end I had to use the brute force solution to delete the rows in the TPC’s SQL DB for the build. I did this in both the tbl_BuildQueue (use the QueueID) and tbl_Build (use the buildID) tables.

Fix for - Could not load file or assembly 'Microsoft.VisualStudio.Shell’ on TFS 2010 Build Controller

I have previously posted about when TFS build controllers don’t start properly. Well I saw the same problem today whilst upgrading a TFS 2010 server to TFS 2012.3. The client did not want to immediately upgrade their build processes and decided to keep their 2010 build VMs just pointing them at the updated server (remember TFS 2012.2 and later servers can support either 2012 or 2010 build controllers).

The problem was that when we restarted the build service the controller and agents appeared to start, but then we got a burst of errors in the event log and we saw the controller say it was ready, but have the stopped icon.

On checking the Windows error log we saw the issue was it could not load the assembly

Exception Message: Problem with loading custom assemblies: Could not load file or assembly 'Microsoft.VisualStudio.Shell, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. (type Exception)

Turns out this was because the StyleCop.VSPackage.dll has been checked into the build controllers CustomAssemblies folder (how and why we never found out, also why it had not failed before was unclear as it was checked in about 6 weeks ago!). Anyway as soon as the DLL was removed from the custom assemblies folder, leaving just the StyleCop files from the c:\program Files (x86)|StyleCop\4.7 folder all was OK.

Moving from Ubuntu to Mint for my TEE demos

I posted a while ago about the problems with DHCP using a Hyper-V virtual switch with WIFI and an Ubuntu VM, well I never found a good solution without hard coding IP addresses.

I recently tried using Mint 15 and was please to see this did not suffer the same problems, it seems happy with DHCP over Hyper-V virtual switches. I think I will give it a go a do a while for any cross platform TEE demos I need for a while.

Update: Just noticed that I still get a DHCP problem with Mint when I connect to my dual band Netgear N600 router via 2.4Ghz, but not when I use the same router via 5Ghz. I just know I am not at the bottom of this problem yet!

Where did that email go?

We use the TFS Alerts system to signal to our teams what state project build are at. So when a developer changes a build quality to ‘ready for test’ an email is sent to everyone in the team and we make sure the build retention policy is set to keep. Now this is not the standard behaviour of the TFS build alerts system, so we do all this by calling a SOAP based web service which in turn uses the TFS API.

This had all been working well until we did some tidying up and patching on our Exchange server. The new behaviour was:

  • Email sent directly via SMTP by the TFS Alert system  worked
  • Email sent via our web service called by the TFS Alert system disappeared, but no errors were shown

As far as we could see emails were leaving our web service (which was running as the same domain service account as TFS, but its own AppPool) and dying inside our email system, we presumed due to some spam filter rule?

After a bit of digging we spotted the real problem.

If you look at the advanced settings of the TFS Alerts email configuration it points out that if you don’t supply credentials for the SMTP server it passes those for the TFS Service process

image

Historically our internal SMTP server had allowed anonymous posting so this was not an issue, but in our tidy it now required authentication, so this setting became important.

We thought this should not be an issue as the TFS service account was correctly registered in Exchange, and it was working for the TFS generated alert emails, but on checking the code of the web service noticed a vital missing line, we were not setting the credentials on the message, we were leaving it as anonymous, so the email was being blocked

using (var msg = new MailMessage())
            {
                msg.To.Add(to);
                msg.From = new MailAddress(this.fromAddress);
                msg.Subject = subject;
                msg.IsBodyHtml = true;
                msg.Body = body;
                using (var client = new SmtpClient(this.smptServer))
                {
                    client.Credentials = CredentialCache.DefaultNetworkCredentials;
                    client.Send(msg);
                }

            }

Once this line was added and the web service redeployed it worked as expect again

Why is my TFS Lab build picking a really old build to deploy?

I was working on a TFS lab deployment today and to speed up testing I set it to pick the <Latest> build of the TFS build that actually builds the code, as opposed to queuing a new one each time. It took me ages to remember/realise why it kept trying to deploy some ancient build that had long since been deleted from my test system.

image

The reason was the <Latest> build means the last successful build, not the last partially successful build. I had a problem with my code build that means a test was failing (a custom build activity on my build agent was the root cause if the issue). Once I fixed my build box so the code build did not fail the lab build was able to pickup the files I expected and deploy them

Note that if you tell the lab deploy build to queue it’s own build it all attempt to deploy this even if it is partially successful.