Assigning TestCases to TestFolders via Rally web service - c#

I have a situation where there are lots of test cases that don't belong to a test folder. This is fine, but I'd like to write an application to move these 'orphaned' test cases into a test folder (mostly so it's easy to easily see how the tests are doing)
All of the test cases and the test folder I create are in the same project, but I get the following errors;
Validation error: TestFolder.TestCases is an invalid relationship. One or more of the artifacts is in a different project.
Validation error: TestCase.TestFolder is an invalid relationship. One or more of the artifacts is in a different project.
These seem to be telling me that I am assigning the test cases to a test folder in a different project - but they aren't.
Here's a snip of the code - m_currentRallyProject and m_workspace have already been set by a different method
Any thoughts?
public void CreateTestFolderForOrphanedTestCases(HierarchicalRequirement aUserStory, List<TestCase> testCases)
{
TestFolder myNewTestFolder = createTestFolder(aUserStory.Name);
for (int i = 0; i < testCases.Count; i++)
{
TestCase myTestCase = (TestCase)testCases[i];
myTestCase.TestFolder = myNewTestFolder;
OperationResult myResult = m_rallyService.update(myTestCase);
if (hasErrors(myResult))
{
updateStatus("Could not set Test Folder for " + myTestCase.FormattedID);
printWarningsErrors(myResult);
}
else
{
updateStatus("updated test case " + myTestCase.FormattedID);
}
}
}
private TestFolder createTestFolder(String testFolderName, TestFolder aParentTestFolder = null)
{
TestFolder myNewTestFolder = new TestFolder();
myNewTestFolder.Name = testFolderName;
myNewTestFolder.Project = m_currentRallyProject;
myNewTestFolder.Workspace = m_workspace;
CreateResult createTestFolderResult = m_rallyService.create(myNewTestFolder);
if (hasErrors(createTestFolderResult))
{
// something went wrong
Console.WriteLine("Could not create Test Folder");
printWarningsErrors(createTestFolderResult);
}
else
{
myNewTestFolder = (TestFolder)m_rallyService.read(createTestFolderResult.Object);
return myNewTestFolder;
}
return null;
}

Dropping an answer in from the comments above :)
Make certain they're in the same project - you shouldn't get this message if they are. Being in the same Project Hierarchy doesn't count. I.E. a Test Folder that is in a Child Project of the current Project, even with child scoping down = true, counts as being in a different Project. Try adding some logging that outputs the Project Name or ref for both the Test Case and the Target Test Folder.
If you add some logging that outputs Project metadata for both TestCase and target TestFolder, make sure to output both Name and ref - since Project Name is not guaranteed to be unique (different Rally Projects can have the same Name).

Related

Tfs Check-in using PendAdd: The array must contain at least one element

So I'm having a problem with automating my code to check-in files to TFS, and it's been driving me up the wall! Here is my code:
string location = AppDomain.CurrentDomain.BaseDirectory;
TfsTeamProjectCollection baseUserTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection);
IIdentityManagementService ims = baseUserTpcConnection.GetService<IIdentityManagementService>();
TeamFoundationIdentity identity = ims.ReadIdentity(IdentitySearchFactor.AccountName, #"PROD1\JR", MembershipQuery.None, ReadIdentityOptions.None);
TfsTeamProjectCollection impersonatedTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection, identity.Descriptor);
VersionControlServer sourceControl = impersonatedTpcConnection.GetService<VersionControlServer>();
Workspace workspace = sourceControl.CreateWorkspace("MyTempWorkspace", sourceControl.AuthorizedUser);
String topDir = null;
try
{
Directory.CreateDirectory(location + "TFS");
String localDir = location + "TFS";
workspace.Map("$/Automation/", localDir);
workspace.Get();
destinationFile = Path.Combine(localDir, Name + ".xml");
string SeconddestinationFile = Path.Combine(localDir, Name + ".ial");
bool check = sourceControl.ServerItemExists(destinationFile, ItemType.Any);
PendingChange[] pendingChanges;
File.Move(sourceFile, destinationFile);
File.Copy(destinationFile, sourceFile, true);
File.Move(SecondsourceFile, SeconddestinationFile);
File.Copy(SeconddestinationFile, SecondsourceFile, true);
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
else
{
workspace.PendEdit(destinationFile);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
and the problem is that whenever it's NEW files (PendEdit works correctly when the files already exist in TFS) that my code is attempting to check in, and it runs through this code:
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
The files, instead of being in the included changes in pending changes, are instead in the excluded changes like so:
and when the line that actually does the check-in runs, I'll get a "The array must contain at least one element" error, and the only way to fix it is to manually add those detected changes, and promote them to included changes, and I simply can't for the life of me figure out how to do that programatically though C#. If anyone has any guidance on what direction I should take for this, I would really appreciate it! Thank you!
Edit: I've also discovered another way to solve this by reconciling the folder, which also promotes the detected changes, but again the problem is I can't seem to figure out how to program that to do it automatically.
I know that running the visual studio developer command prompt, redirecting to the folder that this mapping is in, and the running "tf reconcile /promote" is one way, but I can only automate that as far as the /promote part, because that brings up a toolbox that a user would have to input into, which defeats the purpose of the automation. I'm at a loss.
Next Edit in response to TToni:
Next Edit in response to TToni:
I'm not entirely sure if I did this CreateWorkspaceParameters correctly (see picture 1), but this time it gave the same error, but the files were not even in the excluded portions. They just didn't show up anywhere in the pending changes (see picture 2).
Check this blog:
The workspace has a method GetPendingChangesWithCandidates, which actually gets all the “Excluded” changes. Code snippet is as below:
private void PendChangesAndCheckIn(string pathToWorkspace)
{
//Get Version Control Server object
VersionControlServer vs = collection.GetService(typeof
(VersionControlServer)) as VersionControlServer;
Workspace ws = vs.TryGetWorkspace(pathToWorkspace);
//Do Delete and Copy Actions to local path
//Create a item spec from the server Path
PendingChange[] candidateChanges = null;
string serverPath = ws.GetServerItemForLocalItem(pathToWorkspace);
List<ItemSpec> its = new List<ItemSpec>();
its.Add(new ItemSpec(serverPath, RecursionType.Full));
//get all candidate changes and promote them to included changes
ws.GetPendingChangesWithCandidates(its.ToArray(), true,
out candidateChanges);
foreach (var change in candidateChanges)
{
if (change.IsAdd)
{
ws.PendAdd(change.LocalItem);
}
else if (change.IsDelete)
{
ws.PendDelete(change.LocalItem);
}
}
//Check In all pending changes
ws.CheckIn(ws.GetPendingChanges(), "This is a comment");
}

SharpShell server .dll NOT signed

I need to develop a Shell Context Menu extension that references some other custom assemblies... I don't want to assign a Strong Name Key to those custom assemblies!
The guide I followed to do this uses the SharpShell project and illustrates how to sign (but does not expalins why) the assembly... and this is my problem: if I sign my final .dll then I have many errors during my project's building phase, because some assemblies my project references are not strongly named ("Referenced assembly does not have a strong name").
In general, googling about the C# Shell Extension implementation, all best tutorials I found sign the final assembly... is it mandatory?
Without signing the assembly ServerManager.exe returns this error: "The file 'XYZ.dll' is not a SharpShell Server".
Finally I've solved my troubles... the SharpShell.dll file obtained through NuGet was a different version of the ServerManager.exe ones.
Uninstalling the SharpShell NuGet package and directly referencing the SharpShell.dll you find inside the ServerManager folder was my solution!
Moreover, I was looking between the article comments... please read this question.
You don't need to use old DLL.
Please use this code directly, without using ServerManager.exe.
private static ServerEntry serverEntry = null;
public static ServerEntry SelectedServerEntry
{
get
{
if (serverEntry == null)
serverEntry = ServerManagerApi.LoadServer("xxx.dll");
return serverEntry;
}
}
public static ServerEntry LoadServer(string path)
{
try
{
// Create a server entry for the server.
var serverEntry = new ServerEntry();
// Set the data.
serverEntry.ServerName = Path.GetFileNameWithoutExtension(path);
serverEntry.ServerPath = path;
// Create an assembly catalog for the assembly and a container from it.
var catalog = new AssemblyCatalog(Path.GetFullPath(path));
var container = new CompositionContainer(catalog);
// Get the exported server.
var server = container.GetExport<ISharpShellServer>().Value;
serverEntry.ServerType = server.ServerType;
serverEntry.ClassId = server.GetType().GUID;
serverEntry.Server = server;
return serverEntry;
}
catch (Exception)
{
// It's almost certainly not a COM server.
MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning");
return null;
}
}
Install code:
ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true);
Register code:
ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit);

Dynamic Flat File Source Path

I'm trying to pass a dynamic file path to a SSIS package variable. I'm setting the ConnectionString value to the variable value in the connection expressions.
So to get started I set the initial variable name value to products.csv and get the error:
Nonfatal errors occurred while saving the package: The name cannot
contain any of the following characters: / \ : [ ] . =
I remove the .csv from the variable name, since I'm passing this value from code anyways - no biggie. But when I pass the appropriate variables and execute the package I get weirdness. I check the db and the expected values from the package are there, but I get a failure status and errors similar to the one I mentioned above.
Below is my code:
GeneralUtilities.ExecutePackage(
new ListDictionary()
{
{"ClientId", Client.Id},
{"FileName", ConfigurationManager.AppSettings["DownloadLocation"] + #"\" + this.OriginalName}
},
"Products.dtsx");
public static void ExecutePackage(ListDictionary variables, string packageName)
{
string pkgLocation;
Package pkg;
Application app;
DTSExecResult pkgResults;
Variables vars;
pkgLocation = ConfigurationManager.AppSettings["PackageLocation"] + packageName;
app = new Application();
using (pkg = app.LoadPackage(pkgLocation, null))
{
vars = pkg.Variables;
foreach (DictionaryEntry variable in variables)
{
vars[variable.Key].Value = variable.Value;
}
pkgResults = pkg.Execute(null, vars, null, null, null);
for(int i=0;i<pkg.Errors.Count;i++)
Console.WriteLine(pkg.Errors[i].Description);
Console.WriteLine(pkgResults.ToString());
}
}
And here's the output:
It's cool that it's being input into the db, but I don't think the Failure message will work. Seems like a package setting or something that is causing a 'false failure'. Can anyone provide help? Thanks.
At this point, I think we need more information. I built out a sample package that imports a CSV; defined 2 variables as indicated (ClientId & FileName); configured the package to use a variable for the CM's ConnectionString property. Finally, I used your your code to run the package. I received no errors.
I was not familiar with the Execute method that takes parameters so I tested your code with both versions of pkg.Execute and the results are the same (you can observe this by saving out the modified package as I do so on the final line and comparing them). Before execution, my variables look like
ClientId: 0
FileName: C:\ssisdata\so\so_matt.csv
RowCount: 0
After execution and saving as so_JeffBorden2.dtsx my variables have been modified as expected.
ClientId: 100
FileName: C:\ssisdata\so\so_matt2.csv
RowCount: 10
private static void so_JeffBorden()
{
string path = #"C:\sandbox\SSISHackAndSlash2008\SSISHackAndSlash2008\so_JeffBorden.dtsx";
ListDictionary variables;
variables = new ListDictionary()
{
{"ClientId", 100},
{"FileName", #"C:\ssisdata\so\so_matt2.csv"}
};
string pkgLocation;
Package pkg;
Application app;
DTSExecResult pkgResults;
Variables vars;
pkgLocation = path;
app = new Application();
using (pkg = app.LoadPackage(pkgLocation, null))
{
vars = pkg.Variables;
foreach (DictionaryEntry variable in variables)
{
vars[variable.Key].Value = variable.Value;
}
pkgResults = pkg.Execute(null, vars, null, null, null);
//pkgResults = pkg.Execute();
for (int i = 0; i < pkg.Errors.Count; i++)
Console.WriteLine(pkg.Errors[i].Description);
Console.WriteLine(pkgResults.ToString());
app.SaveToXml(#"C:\sandbox\SSISHackAndSlash2008\SSISHackAndSlash2008\so_JeffBorden2.dtsx", pkg, null);
}
}
Is there something cut from your sample code that was needed to generate the error? If you run your full code against my sample package, do you encounter errors?
Root cause
The error in the screenshot indicates there is an expression assigning a value to the Name property of an object. Names in SSIS generally follow the .NET rules for naming (connection managers excluded). There are 5 total objects in this package: two variables and a data flow which contains 3 items (I'm not good at math). The variables are not having their name property modified based on the supplied code. The names of the components in the data flow are all the default names which leaves the data flow's name as the prime suspect. Note that the name of the data flow products is an identical match to the value of the variable #[User::FileName] The problem only surfaces when the package executes which is the only time the value of FileName would change.
To test this, in BIDS/SSDT modify the value of variable FileName to be 'doh.txt' and the package should start throwing errors due to bad name.
To resolve this, right click on the data flow and either delete the expression on the Name property or sanitize the string by removing the offending characters in the expression (liberal use of REPLACE will do the trick)

Simple ASMX WebService and DLL not loaded

I've a problem running an ASMX Web Service. I'm Calling a DLL from a method (AceptaTools.dll) and this DLL load ca4xml.dll.
AceptaTools.dll has been registered with REGSVR32. But ca4xml.dll Can't.
When i Invoke the service:
_objURL = _CA4XML.GetLastResponse();
i get a message "ca4xml.dll not loaded".
Looking al Dependency Walker:
Here both files in detail:
Both DLL are in BIN folder and my project run as x86... Why can't load?? Please help.
[WebMethod]
public string Send(string Ip, string Puerto, string NroDocumento, string TipoDocumento, string Comando, string Impresora, string Linea)
{
try
{
int _Result = 0;
string _Null = "";
string _objURL;
//Config Capsula
string serverConfig = "cfg|" + Ip.ToString() + "|" + Puerto.ToString() + "|10";
//Impresora FACTURA,1 por Defecto.
if (string.IsNullOrEmpty(Impresora)) { Impresora = "FACTURA,1"; }
if (string.IsNullOrEmpty(NroDocumento)) { NroDocumento = "0"; }
if (string.IsNullOrEmpty(Comando)) { Comando = "generar"; }
//Nuevo CAXML Cliente
AceptaTools.CA4XML_Client _CA4XML = new CA4XML_Client();
_Result = _CA4XML.Send(ref serverConfig, ref NroDocumento, ref Comando, ref Impresora, ref Linea, out _Null);
if (_Result != 0)
{
_objURL = _CA4XML.GetLastResponse(); //Get URL
return _objURL.ToString();
}
else
{
return "Error";
}
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
}
Did you make sure that the ca4xml.dll is deployed properly? Since I guess it is not referenced as .NET assembly the VS will treat it like a normal file and you will need to specifically tell VS to include it when deploying.
Do the following steps to check whether deployment has been setup properly:
Open the Solution Explorer -> Got to the ca4xml.dll -> Right click -> Select Properties -> Set Build Action = None & Copy to Output = Always
Also in addition to the Dependency Walker I suggest to use Process Monitor. When you use the file access view (disregarding registry changes etc.) you can see all the locations where a process tries to load a dll from. Afterwards you can make sure that the dll you are missing is in one of the listed locations, here is the link:
http://technet.microsoft.com/en-us/sysinternals/bb896645
When you do not load DLL in the program because you need to update some things .
you can update project in nuget manager

Windows service - how to make name configurable

I have written a windows service in C#. The requirement at the beginning was that I should be running only one instance of that service, but that has changed and now I need multiple instances. This is why I need to change the service name according to the configuration file.
What would be the best way to make it register with the correct name ? Should I write another tool to do it? Can I just read the name from App.config file and set it in the service and installer classes accordingly ?
PS> I do not really understand how that thing with names work - one should set names in service and installer classes, but then when installing with installutil.exe or even powershell new-service the name also should be specified. Does that have to be the same? Or one overrides another?
You can simply read it from the app.config and set it in the installer classes.
Normally, a class that inherits from Installer is automatically created. It contains a member of type System.ServiceProcess.ServiceInstaller, most likely named serviceProcessInstaller1. This has a property ServiceName you can set. Additionally, you need to set the ServiceName property of the ServiceBase derived class to the same value.
In a default implementation, these are set to constant values in the respective InitializeComponent methods, but there is no reason to stick with this. It can be done dynamically without problems.
I though I'd add my 2 cents since I ran into this. I have a file called "ProjectInstaller.cs" with designer and resources under it. Opening it up in design shows MyServiceInstaller and MyProjectInstaller as items on the design surface. I was able to change the names in the ProjectInstaller() constructor, and manually loaded the config file from the module directory:
public ProjectInstaller()
{
InitializeComponent();
var config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
if (config.AppSettings.Settings["ServiceName"] != null)
{
this.MyServiceInstaller.ServiceName = config.AppSettings.Settings["ServiceName"].Value;
}
if (config.AppSettings.Settings["DisplayName"] != null)
{
this.MyServiceInstaller.DisplayName = config.AppSettings.Settings["DisplayName"].Value;
}
}
In the same vein as Jason Goemaat's answer, this is how you would loop through all available installers in your project, which saves you the time of being sure you added each new service to this class. In my project, I have a total of 12 services (and we add a new one here and there), and we wanted them grouped together by the instance name, so SVC (Instance 1) Service XX and SVC (Instance 1) Service YY were next to each other when viewed in the services snap-in console.
public ProjectInstaller()
{
InitializeComponent();
var config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
string instanceName = config.AppSettings.Settings["Installer_NamedInstanceName"].Value;
string instanceID = config.AppSettings.Settings["Installer_NamedInstanceID"].Value;
bool usesNamedInstance = !string.IsNullOrWhiteSpace(instanceName) && !string.IsNullOrWhiteSpace(instanceID);
if (usesNamedInstance)
{
foreach (var installer in this.Installers)
{
if (installer is ServiceInstaller)
{
var ins = (ServiceInstaller)installer;
ins.ServiceName = ins.ServiceName + "-" + instanceID;
// Want the service to be named SVC (Instance Name) Audit Log Blah Blah Service
ins.DisplayName = ins.DisplayName.Replace("SVC ", "SVC (" + instanceName + ") ");
}
}
}
}
HOWEVER, there is something else that you need to do - When initializing the service, you must also change the service name, otherwise you'll get an error along the lines of "The executable doesn't implement the service". I did this by implementing the following code in Program.cs:
internal static void HandleCustomServiceName(ServiceBase sbase)
{
if (!string.IsNullOrWhiteSpace(customInstanceName))
{
sbase.ServiceName = sbase.ServiceName + "-" + customInstanceName;
}
}
Then, in the constructor of each service:
public SystemEventWatcher()
{
InitializeComponent();
Program.HandleCustomServiceName(this);
}
I've upvoted Jason's answer for paving the way to implementing this in my own project. Thanks!

Categories