Tuesday, 19 January 2016

Update Script Timeout in MTM Test Settings

You could run into default script timeout of five minutes, while running scripts before running tests using MTM.

image

image

Error    1/19/2016 11:10:39 AM    The setup batch file on agent machine 'vstfs:///LabManagement/TestMachine/19' exceeded the execution timeout period.    vstfs:///LabManagement/TestMachine/19

How to Resolve

To increase this timeout there is no straight forward way using MTM. However update deployment timeout is explained in here, utilizing the tool created by Aseem Bansal. But setting Script timeout not available with this particular tool.

As explained in this MSDN Q&A, I have made changes to the code downloaded from the post here by Aseem Bansal and improved it to enable setting the Script Timeout for test settings. You can download the new utility from Technet Gallery here, and use it as explained below (VS 2013 source code for the tool available here). 

UpdateTestSettings /collection:<ProjectCollectionUri> /teamProject:<ProjectName> /settingsname:<TestSettingsName> [/bucketSize:<value>] [/deploymentTimeout:<value>] [/scriptTimeout:<value>]

Examples:

UpdateTestSettings /collection:http://abc:8080/tfs/DefaultCollection /teamProject:myProject /settingsname:My2_0_App /bucketSize:200 /deploymentTimeout:600000

UpdateTestSettings /collection:http://abc:8080/tfs/DefaultCollection /teamProject:myProject /settingsname:My2_0_App /bucketSize:200 /deploymentTimeout:600000 /scriptTimeout:900000

UpdateTestSettings /collection:http://abc:8080/tfs/DefaultCollection /teamProjec:myProject /settingsname:My2_0_App /scriptTimeout:900000

Utility improved to provide Test Settings infor before and after update.
 image

How the code is modified

You can download the original code for the utility from the link provided in the post here.

image

image

When this is built with VS 2013 there could be below errors if you do not have VS 2010 in your machine.image

With or without having above errors remove the references for TeamFoundation dlls.image

There is no Microsoft.TeamFoundation.dll for VS 2013. Microsoft.TeamFoundation.Common.dll would add all thats is added previously by Microsoft.TeamFoundation.dll. Add the references to Team Foundation dlls.image

Remove “Read only” from all code files downloaded before change framework.image

Set the framework to 4.5 and you can build the code with VS 2013 successflully.image

Replace the code in Program.cs with the below updated Program.cs code.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
// ---------------------------------------------------------------------------
// <copyright file="Program.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <summary>
//   Updates the specified properties in the tcm test settings.
// 
//   MTM UI does not expose updation of bunch of test settings properties
//   but the same can be achieved via the TCM APIs. This utility uses those
//   APIs to update the following properties in tcm test settings. 
// 
//   1. Deployment timeout. 
//   2. Bucket size. 
//   3. Apartment state. 
// 
// Introduced ScriptTimeout - Chaminda Chandrasekara 19/01/2016
// </summary>
// ---------------------------------------------------------------------------

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.TestManagement.Client;
using Microsoft.VisualStudio.TestTools.Common;
using Microsoft.VisualStudio.TestTools.Common.Xml;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Xml;

namespace UpdateTestSettings
{
    class Program
    {
        static void Main(string[] args)
        {
            CommandParameters commandParameters;

            Console.WriteLine();
            Console.WriteLine();

            // Validate the parameters
            ValidateArguments(args, out commandParameters);
            Console.WriteLine("Using parameters: {0}", commandParameters);


            // Connect to the team project. 
            TfsTeamProjectCollection collection = new TfsTeamProjectCollection(new Uri(commandParameters.ProjectCollectionUri));
            TestManagementService tcmService = collection.GetService<TestManagementService>();
            ITestManagementTeamProject teamProject = tcmService.GetTeamProject(commandParameters.ProjectName);
            Console.WriteLine("Connected to the team project {0}.", commandParameters.ProjectName);


            // Find the specified test settings.
            TestRunConfiguration testRunConfiguration = null;
            ITestSettings testSetting = FindTestSettings(commandParameters.TestSettingsName, teamProject, out testRunConfiguration);
            
            // Get ScriptTimeout hidden property info
            PropertyInfo pInfo = testRunConfiguration.GetType().GetProperty("ScriptTimeout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
            Console.WriteLine("==============================================================");
            Console.WriteLine("Current TestSettings {0} has bucketSize={1}, deploymentTimeout={2}, scriptTimeout={3}  and ApartmentState={4}.", testSetting.Name, testRunConfiguration.BucketSize, testRunConfiguration.DeploymentTimeout, pInfo.GetValue(testRunConfiguration, null), testRunConfiguration.ApartmentState);
            Console.WriteLine("==============================================================");

            Console.WriteLine("Found the testsettings named {0}.", commandParameters.TestSettingsName);

            // If it is an update command, then update the settings
            if (commandParameters.IsUpdate)
            {
                UpdateTestSettings(testSetting, testRunConfiguration, commandParameters);
                Console.WriteLine("Updated the testsettings.");
                Console.WriteLine();
            }

            // Show the new values to the user
            
            // Reload test configurations after update
            FindTestSettings(commandParameters.TestSettingsName, teamProject, out testRunConfiguration);

            Console.WriteLine("==============================================================");
            Console.WriteLine("Updated TestSettings {0} has bucketSize={1}, deploymentTimeout={2}, scriptTimeout={3}  and ApartmentState={4}.", testSetting.Name, testRunConfiguration.BucketSize, testRunConfiguration.DeploymentTimeout, pInfo.GetValue(testRunConfiguration, null),testRunConfiguration.ApartmentState);
            Console.WriteLine("==============================================================");
        }

        /// <summary>
        /// Update the tcm test settings as per the specified command-line parameters
        /// </summary>
        private static void UpdateTestSettings(ITestSettings testSetting, 
                                               TestRunConfiguration testRunConfiguration, 
                                               CommandParameters commandParameters)
        {
            if (commandParameters.HasBucketSize)
            {
                testRunConfiguration.BucketSize = commandParameters.BucketSize;
            }
            if (commandParameters.HasDeploymentTimeout)
            {
                testRunConfiguration.DeploymentTimeout = commandParameters.DeploymentTimeout; 
            }
            if (commandParameters.HasApartmentState)
            {
                testRunConfiguration.ApartmentState = commandParameters.ApartmentState;
            }
            if (commandParameters.HasScriptTimeout)
            {
                PropertyInfo pInfo = testRunConfiguration.GetType().GetProperty("ScriptTimeout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);

                pInfo.SetValue(testRunConfiguration, commandParameters.ScriptTimeout, null);
            }

            // Tcm test settings contains the TestRunConfiguration xml which has all the settings information. 
            // During the update, we update the testRunConfiguration xml in the test settings
            //
            XmlElement element = LocalXmlPersistence.SaveTestRunConfiguration(testRunConfiguration);
            testSetting.Settings = element;

            testSetting.Save();
        }


        /// <summary>
        /// Find the parameter test settings on the team project
        /// </summary>
        private static ITestSettings FindTestSettings(string testSettingsName, 
                                                      ITestManagementTeamProject teamProject, 
                                                      out TestRunConfiguration testRunConfiguration)
        {
            Console.WriteLine("Finding the testsettings named {0}.", testSettingsName);
            ITestSettings testSetting = null;
            IEnumerable<ITestSettings> testSettings = teamProject.TestSettings.Query("SELECT * FROM TestSettings");

            StringBuilder availableSettings = new StringBuilder();
            foreach (ITestSettings setting in testSettings)
            {
                if (string.Equals(setting.Name, testSettingsName, StringComparison.OrdinalIgnoreCase))
                {
                    if (!setting.IsAutomated)
                    {
                        Console.Error.WriteLine("Warning!! Ignoring testsettings named {0} (with id {1}) as it is a manual testsettings. You should specify only the automated testsettings.", setting.Name, setting.Id);
                        continue;
                    }

                    testSetting = setting;
                    break;
                }

                // We dont want to pick the manual test settings. 
                if (!setting.IsAutomated)
                {
                    continue;
                }
                else
                {
                    if (availableSettings.Length > 0)
                    {
                        availableSettings.Append(",");
                    }

                    availableSettings.Append("\"");
                    availableSettings.Append(setting.Name);
                    availableSettings.Append("\"");
                }
            }

            // Throw error if setting is not found. 
            //
            if (testSetting == null)
            {
                testRunConfiguration = null;

                if (string.IsNullOrEmpty(availableSettings.ToString()))
                {
                    throw new Exception(string.Format(CultureInfo.InvariantCulture, "No automated testsettings found with name {0}. Additionally there is no automated testsettings available in this project. So create an automated testsettings using 'Microsoft Test Manager' and then try again.", testSettingsName));
                }
                else
                {
                    throw new Exception(string.Format(CultureInfo.InvariantCulture, "No automated testsettings found with name {0}. The available automated testsettings are: {1}", testSettingsName, availableSettings));
                }
            }

            // Load the xml from the txm settings into TestRun configuration
            testRunConfiguration = new TestRunConfiguration(testSetting.Name, "dummy");
            testRunConfiguration.Load(testSetting.Settings, XmlTestStoreParameters.GetParameters());
            testRunConfiguration.Name = testSetting.Name;

            return testSetting;
        }


        /// <summary>
        /// Validate the command-line parameters
        /// </summary>
        private static void ValidateArguments(string[] args, out CommandParameters commandParameters)
        {
            if (args.Contains("?", StringComparer.OrdinalIgnoreCase)
                || args.Contains("/?", StringComparer.OrdinalIgnoreCase))
            {
                ShowHelpMessage();
                Environment.Exit(-1);
            }

            string collectionSwitch = "/collection:";
            string projectSwitch = "/teamProject:";
            string testSettingsSwitch = "/settingsname:";
            string bucketSizeSwitch = "/bucketsize:";
            string deploymentTimeoutSwitch = "/deploymentTimeout:";
            string scriptTimeoutSwitch = "/scriptTimeout:";
            string apartmentStateSwitch = "/apartmentState:";
            

            string projectCollectionUri = null;
            string teamProjectName = null;
            string testSettingsName = null;
            int bucketSize = -1;
            int deploymentTimeout = -1;
            int scriptTimeout = -1;
            ApartmentState apartmentState = ApartmentState.Unknown;

            foreach (string argument in args)
            {
                if (argument.StartsWith(collectionSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    projectCollectionUri = argument.Substring(collectionSwitch.Length);
                }
                else if (argument.StartsWith(projectSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    teamProjectName = argument.Substring(projectSwitch.Length);
                }
                else if (argument.StartsWith(testSettingsSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    testSettingsName = argument.Substring(testSettingsSwitch.Length);
                }
                else if (argument.StartsWith(bucketSizeSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    string bucketSizeValue  = argument.Substring(bucketSizeSwitch.Length);
                    bucketSize = int.Parse(bucketSizeValue);
                }
                else if (argument.StartsWith(deploymentTimeoutSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    string deploymentTimeoutValue = argument.Substring(deploymentTimeoutSwitch.Length);
                    deploymentTimeout = int.Parse(deploymentTimeoutValue);
                }
                else if (argument.StartsWith(scriptTimeoutSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    string scriptTimeoutValue = argument.Substring(scriptTimeoutSwitch.Length);
                    scriptTimeout = int.Parse(scriptTimeoutValue);
                }
                else if (argument.StartsWith(apartmentStateSwitch, StringComparison.OrdinalIgnoreCase))
                {
                    string apartmentStateValue = argument.Substring(apartmentStateSwitch.Length);
                    apartmentState = (ApartmentState)Enum.Parse(typeof(ApartmentState), apartmentStateValue, true);
                }
            }

            bool projectCollectionUriError = false, teamProjectError = false, testSettingsError = false;
            if (string.IsNullOrEmpty(projectCollectionUri))
            {
                projectCollectionUriError = true;
            }
            else if (string.IsNullOrEmpty(teamProjectName))
            {
                teamProjectError = true;
            }
            else if (string.IsNullOrEmpty(testSettingsName))
            {
                testSettingsError = true;
            }

            if (projectCollectionUriError || teamProjectError || testSettingsError)
            {
                if (projectCollectionUriError)
                {
                    Console.Error.WriteLine("ProjectCollectionUri argument is not specified");
                }
                else if (teamProjectError)
                {
                    Console.Error.WriteLine("TeamProjectName argument is not specified");
                }
                else if (testSettingsError)
                {
                    Console.Error.WriteLine("Settingsname argument is not specified");
                }

                ShowHelpMessage();
                Environment.Exit(-1);
            }

            commandParameters = new CommandParameters(projectCollectionUri, teamProjectName, testSettingsName);
            commandParameters.BucketSize = bucketSize;
            commandParameters.DeploymentTimeout = deploymentTimeout;
            commandParameters.ScriptTimeout = scriptTimeout;
            commandParameters.ApartmentState = apartmentState;
        }

        private static void ShowHelpMessage()
        {
            Console.Error.WriteLine("Usage: UpdateTestSettings /collection:<ProjectCollectionUri> /teamProject:<ProjectName> /settingsname:<TestSettingsName> [/bucketSize:<value>] [/deploymentTimeout:<value>] [/apartmentState:<value>]");
            Console.Error.WriteLine();
            Console.Error.WriteLine("Examples:");
            Console.Error.WriteLine("UpdateTestSettings /collection:http://abc:8080/tfs/DefaultCollection /teamProject:myProject /settingsname:My2_0_App /bucketSize:200 /deploymentTimeout:600000 /apartmentState:MTA");
            Console.Error.WriteLine();
            Console.Error.WriteLine("UpdateTestSettings /collection:http://abc:8080/tfs/DefaultCollection /teamProject:myProject /settingsname:My2_0_App");
            Console.Error.WriteLine();
            Console.Error.WriteLine("Default values: BucketSize=100 & DeploymentTimeOut=300000 & ApartmentState=STA.");
        }


    }


    /// <summary>
    /// Helper class to capture the command-line inputs
    /// </summary>
    public class CommandParameters
    {
        private string m_projectCollectionUri;
        private string m_teamProjectName;
        private string m_testSettingsName;

        private int m_bucketSize = -1;
        private int m_deploymentTimeout = -1;
        private int m_scriptTimeout = -1;
        private ApartmentState m_apartmentState = ApartmentState.Unknown;


        public CommandParameters(string projectCollectionUri, string teamProjectName, string testSettingsName)
        {
            Debug.Assert(!string.IsNullOrEmpty(projectCollectionUri), "Project collection uri cannot be empty");
            Debug.Assert(!string.IsNullOrEmpty(teamProjectName), "Team Project name cannot be empty");
            Debug.Assert(!string.IsNullOrEmpty(testSettingsName), "TestSettings name cannot be empty");

            m_projectCollectionUri = projectCollectionUri;
            m_teamProjectName = teamProjectName;
            m_testSettingsName = testSettingsName;
        }

        public string ProjectCollectionUri
        {
            get { return m_projectCollectionUri; }
        }

        public string ProjectName
        {
            get { return m_teamProjectName; }
        }
        public string TestSettingsName
        {
            get { return m_testSettingsName; }
        }

        public int BucketSize
        {
            get { return m_bucketSize; }
            set { m_bucketSize = value; }
        }

        public bool HasBucketSize
        {
            get { return m_bucketSize != -1; }
        }

        public int DeploymentTimeout
        {
            get { return m_deploymentTimeout; }
            set { m_deploymentTimeout = value; }
        }

        public bool HasDeploymentTimeout
        {
            get { return m_deploymentTimeout != -1; }
        }

        public int ScriptTimeout
        {
            get { return m_scriptTimeout; }
            set { m_scriptTimeout = value; }
        }

        public bool HasScriptTimeout
        {
            get { return m_scriptTimeout != -1; }
        }

        public ApartmentState ApartmentState
        {
            get { return m_apartmentState; }
            set { m_apartmentState = value; }
        }

        public bool HasApartmentState
        {
            get { return m_apartmentState != ApartmentState.Unknown; }
        }

        public bool IsUpdate
        {
            get { return (HasBucketSize || HasDeploymentTimeout || HasScriptTimeout|| HasApartmentState); }
        }


        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(string.Format(CultureInfo.CurrentCulture, "Collection={0},", m_projectCollectionUri));
            builder.Append(string.Format(CultureInfo.CurrentCulture, "TeamProject={0},", m_teamProjectName));
            builder.Append(string.Format(CultureInfo.CurrentCulture, "SettingsName={0}", m_testSettingsName));

            if (HasBucketSize)
            {
                builder.Append(",");
                builder.Append(string.Format(CultureInfo.CurrentCulture, "BucketSize={0},", m_bucketSize));
            }

            if (HasDeploymentTimeout)
            {
                builder.Append(",");
                builder.Append(string.Format(CultureInfo.CurrentCulture, "DeploymentTimeout={0},", m_deploymentTimeout));
            }

            if (HasScriptTimeout)
            {
                builder.Append(",");
                builder.Append(string.Format(CultureInfo.CurrentCulture, "ScriptTimeout={0},", m_scriptTimeout));
            }

            if (HasApartmentState)
            {
                builder.Append(",");
                builder.Append(string.Format(CultureInfo.CurrentCulture, "ApartmentState={0},", m_apartmentState));
            }

            return builder.ToString();
        }
 
    }
}

2 comments:

sameera jayawardana said...

This tool works great ...... Thanks

sameera jayawardana said...

This tool works great ...... Thanks