In a previous article i went through how to unit test K2 workflow, now i have some more examples of testing a workflow from start to finish.
These unit tests just use the out of the box K2 API and Visual Studio’s testing framework. It uses an XML file to store test results and data such as task SN and process instance id.
The code can be downloaded from here
Starting the workflow
To start a workflow we can use the following API
// <summary>
/// Starts a workflow
/// </summary>
/// <param name="Folio"></param>
/// <param name="ProcessName"></param>
/// <returns></returns>
public int StartProcess(string Folio, string ProcessName)
{
var con = ConfigurationManager.AppSettings;
int ProcessInstanceId = 0;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
try
{
SourceCode.Workflow.Client.ProcessInstance K2Proc = K2Conn.CreateProcessInstance(ProcessName);
K2Proc.Folio = Folio;
K2Conn.ImpersonateUser(ServiceAccount);
K2Conn.StartProcessInstance(K2Proc);
ProcessInstanceId = K2Proc.ID;
}
catch (Exception EX)
{
ProcessInstanceId = 0;
}
finally
{
K2Conn.Close();
}
return ProcessInstanceId;
}
This method returns the process instance id. We can use this in a unit test and check to see if the value returned from the above method is greater than 0
Test: Unit Test for starting the workflow and check to see if it has started (Common)
/// <summary>
/// Tests the starting of a workflow, should return a number greater than 0
/// </summary>
/// <param name="folio"></param>
/// <param name="ProceesName"></param>
/// <returns></returns>
[TestMethod]
public void StartWorkflow_Success()
{
int actual = workflow.StartProcess(this.folio, this.ProcessName);
this.proceessInstance = actual;
Results.SaveResult(TestType.ProcessInstance,this.proceessInstance.ToString());
Assert.AreNotEqual(0, actual);
ProcInstId = this.proceessInstance;
}
Check the workflow is running
Now that the workflow has started, we can run a method to check it’s current status
/// <summary>
/// Gets the current status of the workflow
/// </summary>
/// <param name="processinstanceId"></param>
/// <returns></returns>
public string GetWorkflowStatus(int processinstanceId)
{
string Result = string.Empty;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
try
{
SourceCode.Workflow.Client.ProcessInstance K2Proc = K2Conn.OpenProcessInstance(processinstanceId);
switch (K2Proc.Status1)
{
case SourceCode.Workflow.Client.ProcessInstance.Status.Active:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Active.ToString();
break;
}case SourceCode.Workflow.Client.ProcessInstance.Status.Completed:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Completed.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Deleted:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Deleted.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Error:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Error.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.New:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.New.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Running:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Running.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Stopped:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Stopped.ToString();
break;
}
}
}
catch (Exception ex)
{ Result = ex.Message; }
finally
{
K2Conn.Close();
}return Result;
}
This method returns the current status, we can use this to see if the current workflow is running or if has completed
Test: Check workflow has started (Common)
/// <summary>
/// Test to check that the workflow has started, by checking it's status
/// </summary>
/// <param name="ProcessInstanceId"></param>
[TestMethod]
public void StartWorkflow_Running_Success()
{
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
string actual = workflow.GetWorkflowStatus(this.proceessInstance);
Results.SaveResult(TestType.StartStatus, actual);
StringAssert.Equals(SourceCode.Workflow.Client.ProcessInstance.Status.Active.ToString(), actual);
}
We could also take this same unit test and change the SourceCode.Workflow.Client.ProcessInstance.Status.Active to ‘Error’ or ‘Completed’
so we can create tests to see if the workflow is completed or it has gone into error state
Checking to see if a task has been created
This method check to see if a task has been created for the particular process and instance.
public Boolean IsTaskFound(int ProcessInstanceId, string ProcessName)
{
Boolean Result = false;
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername, 5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
Result = true;
}
}
}
catch (Exception ex)
{
Result = false;
}
finally
{
wrkmgt.Connection.Close();
}
return Result;
}
Test: Work List – task found (Common)
Returns true if task has been found
/// <summary>
/// Tests to see if tasks have been generated for this instance
/// </summary>
[TestMethod]
public void WorkList_TasksFound_Success()
{
Thread.Sleep(milliseconds);
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
Boolean actual = false;
actual = workflow.IsTaskFound(this.proceessInstance, this.ProcessName);
Assert.AreEqual(true, actual);
}
Checking the correct number of tasks has been created
This method gets the number of tasks that has been generated. So we can check if the correct number of tasks.
public int GetTaskCount(int ProcessInstanceId,string ProcessName)
{
int Result = 0;
int count = 0;
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername ,5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
count++;
}
}
Result = count;
}
catch (Exception ex)
{
Result = 0;
}
finally
{
wrkmgt.Connection.Close();
}
return Result;
}
Test: Correct number of tasks created (Common)
Returns the number of tasks, which we can then compare against the amount expected
/// <summary>
/// Checks that the correct number of tasks is generated
/// </summary>
[TestMethod]
public void WorkList_CorrectNumberOfTasksCreated_Success()
{
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
int actual = 0;
actual = workflow.GetTaskCount(this.proceessInstance, this.ProcessName);
Results.SaveResult(TestType.TaskCount, actual.ToString());
Assert.AreEqual(this.TaskCount, actual);
}
Get task details
This methods takes the task, and gets the details about the task
/// <summary>
/// Gets details about the task
/// </summary>
/// <param name="ProcessInstanceId"></param>
/// <returns></returns>
public List<tasklist> GetTask(int ProcessInstanceId,string ProcessName)
{
List<tasklist> list = new List<tasklist>();
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername, 5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
var x = worklistItem.ActivityName;
list.Add(new tasklist
{
Status = worklistItem.Status.ToString(),
Destination = worklistItem.Destination,
EventName = worklistItem.EventName,
ActInstDestID = worklistItem.ActInstDestID.ToString(),
ActivityName = worklistItem.ActivityName,
SerialNumber = (ProcessInstanceId + "_" + worklistItem.ActInstDestID)
});
}
}
}
catch (Exception ex)
{
// Result = false;
}
finally
{
wrkmgt.Connection.Close();
}
return list;
}
Test: Check that the correct task has been created (Common)
Returns the name of the activity which compares against the expected activity
/// <summary>
/// Gets the activity name of the task
/// </summary>
[TestMethod]
public void WorkList_RetrieveTaskList_Success()
{
string Actual = string.Empty;
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
var task = workflow.GetTask(this.proceessInstance, this.ProcessName);
this.SerialNumber = task[0].SerialNumber;
Results.SaveResult(TestType.SerialNumber, this.SerialNumber);
this.DestinationUser = task[0].Destination;
Results.SaveResult(TestType.Destination, this.DestinationUser);
Actual = task[0].ActivityName;
Results.SaveResult(TestType.TaskActivity, Actual);
Assert.AreEqual(this.TaskActivity, Actual);
}
Action a task
Actions the task and moves the workflow along
/// <summary>
/// Actions a task
/// </summary>
/// <param name="action"></param>
/// <param name="serialnumber"></param>
/// <param name="destinationuser"></param>
/// <returns></returns>
public Boolean ActionTask(string action, string serialnumber, string destinationuser)
{
Boolean result = false;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
K2Conn.ImpersonateUser(destinationuser);
SourceCode.Workflow.Client.WorklistItem K2WListItem = K2Conn.OpenWorklistItem(serialnumber);
try
{
K2WListItem.Actions[action].Execute();
result = true;
}
catch (Exception ex)
{
result = false;
}
finally {
K2Conn.Close();
}
return result;
}
Test : Action’s the task
Returns true if the action of the task has been successful which we compare against the expected.
/// <summary>
/// Actions a task
/// </summary>
[TestMethod]
public void Task_GetActions_Sucess()
{
Boolean Actual = false;
this.SerialNumber = Results.GetResult(TestType.SerialNumber);
this.DestinationUser = Results.GetResult(TestType.Destination);
K2WorkflowMap.TaskDetails task = workflow.OpenTask(this.SerialNumber, this.DestinationUser)[0];
Actual = workflow.ActionTask(this.TaskAction, this.SerialNumber, this.DestinationUser);
Assert.AreEqual(true, Actual);
}
This test only accounts for one slot, it can be modified to loop through the task list for the particular instance.
Task Count
This method, counts the number of tasks for the current instance
/// <summary>
/// Gets the number of active tasks for instance of a workflow
/// </summary>
/// <param name="ProcessInstanceId"></param>
/// <returns></returns>
public int GetTaskCount(int ProcessInstanceId,string ProcessName)
{
int Result = 0;
int count = 0;
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername ,5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
count++;
}
}
Result = count;
}
catch (Exception ex)
{
Result = 0;
}
finally
{
wrkmgt.Connection.Close();
}
return Result;
}
Test: Check Task Complete (Common)
Test checks to see if the number of the tasks for instance is 0
/// <summary>
/// checks to see if task is complete by checking that task has gone
/// </summary>
[TestMethod]
public void Task_CheckTaskComplete_Success()
{
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
int actual = 0;
actual = workflow.GetTaskCount(this.proceessInstance, this.ProcessName);
Results.SaveResult(TestType.TaskCount, actual.ToString());
Assert.AreEqual(0, actual);
}
Once the main lot of testing is complete we can check that that the correct number of activities have been executed and we can check that the correct activities have ran.
Also using the status method we can check if its completed.
Activities correct number
This method gets all the activities that ran during the process instance.
/// <summary>
/// Gets the list of activities from process instance
/// </summary>
/// <param name="processinstanceId"></param>
/// <returns></returns>
public List<Activities> GetActivities(string processinstanceId)
{
List<Activities> list = new List<Activities>();
SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder hostServerConnectionString = new SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder();
hostServerConnectionString.Host = servername;
hostServerConnectionString.Port = 5555;
hostServerConnectionString.IsPrimaryLogin = true;
hostServerConnectionString.Integrated = true;
SourceCode.SmartObjects.Client.SmartObjectClientServer serverName = new SourceCode.SmartObjects.Client.SmartObjectClientServer();
serverName.CreateConnection();
serverName.Connection.Open(hostServerConnectionString.ToString());
try
{
SourceCode.SmartObjects.Client.SmartObject smartObject = serverName.GetSmartObject("Activity_Instance");
smartObject.MethodToExecute = "List";
smartObject.Properties["ProcessInstanceID"].Value = processinstanceId;
SourceCode.SmartObjects.Client.SmartObjectList smoList = serverName.ExecuteList(smartObject);
foreach (SourceCode.SmartObjects.Client.SmartObject item in smoList.SmartObjectsList)
{
int ProcInstId = 0;
int ActInstId = 0;
int.TryParse(item.Properties["ProcessInstanceID"].Value, out ProcInstId);
int.TryParse(item.Properties["ActivityInstanceID"].Value, out ActInstId);
DateTime startDate = DateTime.Today;
DateTime finishDate = DateTime.Today;
DateTime.TryParse(item.Properties["StartDate"].Value, out startDate);
DateTime.TryParse(item.Properties["FinishDate"].Value, out finishDate);
list.Add(new Activities
{
ProcessInstanceId = ProcInstId,
ActivityInstanceId = ActInstId,
ActivityName = item.Properties["ActivityName"].Value,
Status = item.Properties["Status"].Value,
StartDate = startDate,
FinishDate = finishDate
});
}
}
catch (Exception ex)
{
list.Add(new Activities
{
ProcessInstanceId = 0,
ActivityInstanceId = 0,
ActivityName = ex.Message,
Status = "Error",
StartDate = DateTime.Today,
FinishDate = DateTime.Today
});
}
finally {
serverName.Connection.Close();
}
return list;
}
Task: Compare Number Of Activities (Common)
This test compares the number of activities that actually ran for the instance against the number expected
/// <summary>
/// Checks the correct number of activities ran
/// </summary>
[TestMethod]
public void Activities_CompareNumberOfActivities_Success()
{
Thread.Sleep(milliseconds);
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
int NumberOfActivitiesRan = workflow.GetActivities(this.proceessInstance.ToString()).Count;
String[] activities = this.Activities.Split(';');
int count = 0;
foreach (var activity in activities)
{
count++;
}
Assert.AreEqual(count, NumberOfActivitiesRan);
}
Activities than ran
This method loops through the activities that have ran against the an array of activities
public Boolean CompareActivities(int ProcessInstanceId, string Activities)
{
Boolean result = false;
List<Activities> instAct = new List<Activities>();
try
{
instAct = GetActivities(ProcessInstanceId.ToString());
String[] activities = Activities.Split(';');
int count = 0;
int match = 0;
foreach (var activity in activities)
{
var instanceactivity = instAct.Where(p => p.ActivityName == activity);
foreach (var act in instanceactivity)
{
match++;
}
count++;
}
if (count == match)
{ result = true; }
}
catch (Exception ex)
{ }
finally { }
return result;
}
Test: Correct Activities Ran (Common)
This test returns true if the activities ran is the same to the activities in the string array.
/// <summary>
/// Checks the correct activities were executed in correct order
/// </summary>
///
[TestMethod]
public void Activities_CorrectActivitiesRan_Success()
{
Thread.Sleep(milliseconds);
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
Boolean actual = workflow.CompareActivities(this.proceessInstance, this.Activities);
Assert.IsTrue(actual);
}
Code Appendix
Below is the complete code
Interface Iworkflowframework.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace K2WorkflowMap
{
interface Iworkflowframeworkcs
{
int StartProcess(string Folio, string ProcessName);
Boolean IsTaskFound(int ProcessInstanceId, string ProcessName);
int GetTaskCount(int ProcessInstanceId, string ProcessName);
List<tasklist> GetTask(int ProcessInstanceId, string ProcessName);
List<TaskDetails> OpenTask(string serialnumber, string destination);
List<ActionList> WhatCanIdo(SourceCode.Workflow.Client.Actions actions);
Boolean ActionTask(string action, string serialnumber, string destinationuser);
Boolean IsTaskComplete(int ProcInst, int Count, string processname);
Boolean IsTaskComplete(string action, string serialnumber, string destinationuser);
string GetWorkflowStatus(int processinstanceId);
List<dataField> GetProcessDataFields(int processinstanceId);
List<Activities> GetActivities(string processinstanceId);
List<Events> GetEvents(string activityid);
List<ActivityDesign> GetWorkflowActivities(int ProcId);
List<Workflow> GetProcesses();
}
}
Class Model.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace K2WorkflowMap
{
public enum TestToRun
{
Start = 1,
CheckStatus = 2,
TaskExists = 3,
TaskCount = 4,
CheckTask = 5,
OpenTaskDetails = 6,
TaskActions = 7,
CompleteTask = 8,
GetActivities = 9
}
public class tasklist
{
public string ActInstDestID { get; set; }
public string ActivityName { get; set; }
public string EventName { get; set; }
public string Destination { get; set; }
public string Status { get; set; }
public string SerialNumber { get; set; }
}
public class ActionList
{
public string ActionValue { get; set; }
public string ActionText { get; set; }
}
public class TaskDetails
{
public string Status { get; set; }
public string SerialNumber { get; set; }
public SourceCode.Workflow.Client.Actions Actions { get; set; }
public string Data { get; set; }
public string DataFields { get; set; }
}
public class dataField
{
public string Name { get; set; }
public string Value { get; set; }
public string valueType { get; set; }
}
public class Activities
{
public int ActivityInstanceId { get; set; }
public int ProcessInstanceId { get; set; }
public string ActivityName { get; set; }
public DateTime StartDate { get; set; }
public DateTime FinishDate { get; set; }
public String Status { get; set; }
}
public class Events
{
public int ActivityInstanceId { get; set; }
public int ProcessInstanceId { get; set; }
public string EventName { get; set; }
public string Destination { get; set; }
public DateTime StartDate { get; set; }
public DateTime FinishDate { get; set; }
public String Status { get; set; }
}
public class ActivityDesign
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Workflow
{
public int ID { get; set; }
public string Name { get; set; }
}
}
Class Results.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.IO;
namespace K2WorkflowUnitTest
{
public enum TestType
{
ProcessName,
Folio,
ProcessInstance,
StartStatus,
TaskCount,
SerialNumber,
Destination,
TaskActivity,
Actions,
Activities,
}
public enum TestSubTypes
{
Action,
Activity,
Event,
}
public class Results
{
private string assemblyFolder;
private string xmlFileName;
public Results()
{
this.assemblyFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
this.xmlFileName = Path.Combine(assemblyFolder, "DataStoreResults.xml");
}
public void SetUpXML(string ProcessName, string Folio)
{
//Gets the settings file
if (!File.Exists(xmlFileName))
{
XmlTextWriter writer = new XmlTextWriter(xmlFileName, System.Text.Encoding.UTF8);
writer.WriteStartDocument(true);
writer.Formatting = Formatting.Indented;
writer.WriteStartElement("Settings");
writer.WriteStartElement("ProcessName");
writer.WriteString(ProcessName);
writer.WriteEndElement();
writer.WriteStartElement("Folio");
writer.WriteString(Folio);
writer.WriteEndElement();
writer.WriteStartElement("ProcessInstanceId");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteStartElement("StartStatus");
writer.WriteString("Stop");
writer.WriteEndElement();
writer.WriteStartElement("TaskCount");
writer.WriteAttributeString("Actual","0");
writer.WriteEndAttribute();
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteStartElement("SerialNumber");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteStartElement("Destination");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteStartElement("TaskActivity");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteStartElement("Actions");
writer.WriteStartElement("Action");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteStartElement("ActionResult");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteStartElement("Activities");
writer.WriteStartElement("Activity");
writer.WriteString("0");
writer.WriteStartElement("Event");
writer.WriteString("0");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
}
else
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFileName);
xmlDoc.ChildNodes[1].ChildNodes[0].InnerXml = ProcessName;
xmlDoc.ChildNodes[1].ChildNodes[1].InnerXml = Folio;
xmlDoc.Save(xmlFileName);
}
}
/// <summary>
/// Saves the result into XML Document
/// </summary>
/// <param name="testType"></param>
/// <param name="Result"></param>
public void SaveResult(TestType testType, string Result)
{
int childNodeIndex = 0;
childNodeIndex = (int)testType;
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.Load(xmlFileName);
xmlDoc.ChildNodes[1].ChildNodes[childNodeIndex].InnerXml = Result;
xmlDoc.Save(xmlFileName);
}
catch (Exception ex)
{
}
finally
{
}
}
/// <summary>
/// Saves the result of sub node in XML Document
/// </summary>
/// <param name="testType"></param>
/// <param name="subTestType"></param>
/// <param name="Result"></param>
public void SaveResult(TestType testType, TestSubTypes subTestType ,string Result)
{
int childNode = 0;
childNode = (int)testType;
int childNodeIndex = 0;
childNodeIndex = (int)subTestType;
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.Load(xmlFileName);
xmlDoc.ChildNodes[1].ChildNodes[childNode].ChildNodes[childNodeIndex].InnerXml = Result;
xmlDoc.ChildNodes[1].ChildNodes[childNode].ChildNodes[childNodeIndex].Attributes["Name"].Value = Result;
xmlDoc.Save(xmlFileName);
}
catch (Exception ex)
{
}
finally
{
}
}
/// <summary>
/// Gets a saved result
/// </summary>
/// <param name="testType"></param>
/// <returns></returns>
public string GetResult(TestType testType)
{
int childNodeIndex = 0;
childNodeIndex = (int)testType;
string results = string.Empty;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFileName);
results = xmlDoc.ChildNodes[1].ChildNodes[childNodeIndex].InnerXml;
return results;
}
}
}
Class Workflowframework.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
namespace K2WorkflowMap
{
public class WorkflowInstanceFramework : Iworkflowframeworkcs
{
public string servername = "cft-v-k2int02";
public string ServiceAccount = @"CHANNEL4\SVCK2MINTMULEUSER";
/// <summary>
/// Starts a workflow
/// </summary>
/// <param name="Folio"></param>
/// <param name="ProcessName"></param>
/// <returns></returns>
public int StartProcess(string Folio, string ProcessName)
{
var con = ConfigurationManager.AppSettings;
int ProcessInstanceId = 0;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
try
{
SourceCode.Workflow.Client.ProcessInstance K2Proc = K2Conn.CreateProcessInstance(ProcessName);
K2Proc.Folio = Folio;
K2Conn.ImpersonateUser(ServiceAccount);
K2Conn.StartProcessInstance(K2Proc);
ProcessInstanceId = K2Proc.ID;
}
catch (Exception EX)
{
ProcessInstanceId = 0;
}
finally
{
K2Conn.Close();
}
return ProcessInstanceId;
}
/// <summary>
/// Checks to see if there is an task
/// </summary>
/// <param name="ProcessInstanceId"></param>
/// <param name="ProcessName"></param>
/// <returns></returns>
public Boolean IsTaskFound(int ProcessInstanceId, string ProcessName)
{
Boolean Result = false;
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername, 5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
Result = true;
}
}
}
catch (Exception ex)
{
Result = false;
}
finally
{
wrkmgt.Connection.Close();
}
return Result;
}
/// <summary>
/// Gets the number of active tasks for instance of a workflow
/// </summary>
/// <param name="ProcessInstanceId"></param>
/// <returns></returns>
public int GetTaskCount(int ProcessInstanceId,string ProcessName)
{
int Result = 0;
int count = 0;
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername ,5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
count++;
}
}
Result = count;
}
catch (Exception ex)
{
Result = 0;
}
finally
{
wrkmgt.Connection.Close();
}
return Result;
}
/// <summary>
/// Gets details about the task
/// </summary>
/// <param name="ProcessInstanceId"></param>
/// <returns></returns>
public List<tasklist> GetTask(int ProcessInstanceId,string ProcessName)
{
List<tasklist> list = new List<tasklist>();
SourceCode.Workflow.Management.WorkflowManagementServer wrkmgt = new SourceCode.Workflow.Management.WorkflowManagementServer(servername, 5555);
SourceCode.Workflow.Management.WorklistItems worklistItems = null;
wrkmgt.Open();
try
{
worklistItems = wrkmgt.GetWorklistItems("", "", "", "", "", "", "");
foreach (SourceCode.Workflow.Management.WorklistItem worklistItem in worklistItems)
{
if (worklistItem.ProcInstID == ProcessInstanceId)
{
var x = worklistItem.ActivityName;
list.Add(new tasklist
{
Status = worklistItem.Status.ToString(),
Destination = worklistItem.Destination,
EventName = worklistItem.EventName,
ActInstDestID = worklistItem.ActInstDestID.ToString(),
ActivityName = worklistItem.ActivityName,
SerialNumber = (ProcessInstanceId + "_" + worklistItem.ActInstDestID)
});
}
}
}
catch (Exception ex)
{
// Result = false;
}
finally
{
wrkmgt.Connection.Close();
}
return list;
}
/// <summary>
/// Task Details
/// </summary>
/// <param name="serialnumber"></param>
/// <param name="destination"></param>
/// <returns></returns>
public List<TaskDetails> OpenTask(string serialnumber, string destination)
{
List<TaskDetails> list = new List<TaskDetails>();
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
K2Conn.ImpersonateUser(destination);
SourceCode.Workflow.Client.WorklistItem K2WListItem = K2Conn.OpenWorklistItem(serialnumber);
try
{
list.Add(new TaskDetails
{
Status = K2WListItem.Status.ToString(),
SerialNumber = K2WListItem.SerialNumber,
Actions = K2WListItem.Actions,
Data = K2WListItem.Data,
DataFields = K2WListItem.ProcessInstance.DataFields.ToString()
});
K2WListItem.Release();
}
catch (Exception ex)
{
list.Add(new TaskDetails
{
Status = "No Task"
});
}
finally {
K2Conn.Close();
}
return list;
}
/// <summary>
/// List of Actions
/// </summary>
/// <param name="actions"></param>
/// <returns></returns>
public List<ActionList> WhatCanIdo(SourceCode.Workflow.Client.Actions actions)
{
List<ActionList> list = new List<ActionList>();
if (actions != null)
{
foreach (SourceCode.Workflow.Client.Action action in actions)
{
list.Add(new ActionList
{
ActionText = action.Name,
ActionValue = action.Name
});
}
}
else {
list.Add(new ActionList
{
ActionText = "No Action",
ActionValue = "No Action"
});
}
return list;
}
/// <summary>
/// Actions a task
/// </summary>
/// <param name="action"></param>
/// <param name="serialnumber"></param>
/// <param name="destinationuser"></param>
/// <returns></returns>
public Boolean ActionTask(string action, string serialnumber, string destinationuser)
{
Boolean result = false;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
K2Conn.ImpersonateUser(destinationuser);
SourceCode.Workflow.Client.WorklistItem K2WListItem = K2Conn.OpenWorklistItem(serialnumber);
try
{
K2WListItem.Actions[action].Execute();
result = true;
}
catch (Exception ex)
{
result = false;
}
finally {
K2Conn.Close();
}
return result;
}
/// <summary>
/// Checks to see if the task count has decreased
/// </summary>
/// <param name="ProcInst"></param>
/// <param name="Count"></param>
/// <returns></returns>
public Boolean IsTaskComplete(int ProcInst, int Count,string processname)
{
Boolean result = false;
int LastCount = Count;
int NewCount = GetTaskCount(ProcInst,processname);
if (LastCount == Count)
{
result = false;
}
else
{
result = true;
}
return result;
}
/// <summary>
/// Checks to see if the actual task that was actioned has been successful
/// </summary>
/// <param name="action"></param>
/// <param name="serialnumber"></param>
/// <param name="destinationuser"></param>
/// <returns></returns>
public Boolean IsTaskComplete(string action, string serialnumber, string destinationuser)
{
Boolean result = true;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
K2Conn.ImpersonateUser(destinationuser);
SourceCode.Workflow.Client.WorklistItem K2WListItem = K2Conn.OpenWorklistItem(serialnumber);
try
{
K2WListItem.Actions[action].Execute();
result = false;
}
catch (Exception ex)
{
result = true;
}
finally
{
K2Conn.Close();
}
return result;
}
/// <summary>
/// Gets the current status of the workflow
/// </summary>
/// <param name="processinstanceId"></param>
/// <returns></returns>
public string GetWorkflowStatus(int processinstanceId)
{
string Result = string.Empty;
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
try
{
SourceCode.Workflow.Client.ProcessInstance K2Proc = K2Conn.OpenProcessInstance(processinstanceId);
switch (K2Proc.Status1)
{
case SourceCode.Workflow.Client.ProcessInstance.Status.Active:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Active.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Completed:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Completed.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Deleted:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Deleted.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Error:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Error.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.New:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.New.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Running:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Running.ToString();
break;
}
case SourceCode.Workflow.Client.ProcessInstance.Status.Stopped:
{
Result = SourceCode.Workflow.Client.ProcessInstance.Status.Stopped.ToString();
break;
}
}
}
catch (Exception ex)
{ Result = ex.Message; }
finally
{
K2Conn.Close();
}
return Result;
}
/// <summary>
/// Gets the process data fields
/// </summary>
/// <param name="processinstanceId"></param>
/// <returns></returns>
public List<dataField> GetProcessDataFields(int processinstanceId)
{
List<dataField> list = new List<dataField>();
SourceCode.Workflow.Client.Connection K2Conn = new SourceCode.Workflow.Client.Connection();
K2Conn.Open(servername);
try
{
SourceCode.Workflow.Client.ProcessInstance K2Proc = K2Conn.OpenProcessInstance(processinstanceId);
foreach (SourceCode.Workflow.Client.DataField datafield in K2Proc.DataFields)
{
list.Add(new dataField {
Name = datafield.Name,
Value = datafield.Value.ToString(),
valueType = datafield.ValueType.ToString()
});
}
}
catch (Exception ex)
{
list.Add(new dataField
{
Name = "Error",
Value = ex.Message.ToString()
});
}
finally {
K2Conn.Close();
}
return list;
}
public Boolean CompareActivities(int ProcessInstanceId, string Activities)
{
Boolean result = false;
List<Activities> instAct = new List<Activities>();
try
{
instAct = GetActivities(ProcessInstanceId.ToString());
String[] activities = Activities.Split(';');
int count = 0;
int match = 0;
foreach (var activity in activities)
{
var instanceactivity = instAct.Where(p => p.ActivityName == activity);
foreach (var act in instanceactivity)
{
match++;
}
count++;
}
if (count == match)
{ result = true; }
}
catch (Exception ex)
{ }
finally { }
return result;
}
/// <summary>
/// Gets the list of activities from process instance
/// </summary>
/// <param name="processinstanceId"></param>
/// <returns></returns>
public List<Activities> GetActivities(string processinstanceId)
{
List<Activities> list = new List<Activities>();
SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder hostServerConnectionString = new SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder();
hostServerConnectionString.Host = servername;
hostServerConnectionString.Port = 5555;
hostServerConnectionString.IsPrimaryLogin = true;
hostServerConnectionString.Integrated = true;
SourceCode.SmartObjects.Client.SmartObjectClientServer serverName = new SourceCode.SmartObjects.Client.SmartObjectClientServer();
serverName.CreateConnection();
serverName.Connection.Open(hostServerConnectionString.ToString());
try
{
SourceCode.SmartObjects.Client.SmartObject smartObject = serverName.GetSmartObject("Activity_Instance");
smartObject.MethodToExecute = "List";
smartObject.Properties["ProcessInstanceID"].Value = processinstanceId;
SourceCode.SmartObjects.Client.SmartObjectList smoList = serverName.ExecuteList(smartObject);
foreach (SourceCode.SmartObjects.Client.SmartObject item in smoList.SmartObjectsList)
{
int ProcInstId = 0;
int ActInstId = 0;
int.TryParse(item.Properties["ProcessInstanceID"].Value, out ProcInstId);
int.TryParse(item.Properties["ActivityInstanceID"].Value, out ActInstId);
DateTime startDate = DateTime.Today;
DateTime finishDate = DateTime.Today;
DateTime.TryParse(item.Properties["StartDate"].Value, out startDate);
DateTime.TryParse(item.Properties["FinishDate"].Value, out finishDate);
list.Add(new Activities
{
ProcessInstanceId = ProcInstId,
ActivityInstanceId = ActInstId,
ActivityName = item.Properties["ActivityName"].Value,
Status = item.Properties["Status"].Value,
StartDate = startDate,
FinishDate = finishDate
});
}
}
catch (Exception ex)
{
list.Add(new Activities
{
ProcessInstanceId = 0,
ActivityInstanceId = 0,
ActivityName = ex.Message,
Status = "Error",
StartDate = DateTime.Today,
FinishDate = DateTime.Today
});
}
finally {
serverName.Connection.Close();
}
return list;
}
/// <summary>
/// Gets a list of Events for an activity
/// </summary>
/// <param name="activityid"></param>
/// <returns></returns>
public List<Events> GetEvents(string activityid)
{
List<Events> list = new List<Events>();
SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder hostServerConnectionString = new SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder();
hostServerConnectionString.Host = servername;
hostServerConnectionString.Port = 5555;
hostServerConnectionString.IsPrimaryLogin = true;
hostServerConnectionString.Integrated = true;
SourceCode.SmartObjects.Client.SmartObjectClientServer serverName = new SourceCode.SmartObjects.Client.SmartObjectClientServer();
serverName.CreateConnection();
serverName.Connection.Open(hostServerConnectionString.ToString());
try
{
SourceCode.SmartObjects.Client.SmartObject smartObject = serverName.GetSmartObject("Event_Instance");
smartObject.MethodToExecute = "List";
smartObject.Properties["ActivityInstanceID"].Value = activityid;
SourceCode.SmartObjects.Client.SmartObjectList smoList = serverName.ExecuteList(smartObject);
foreach (SourceCode.SmartObjects.Client.SmartObject item in smoList.SmartObjectsList)
{
int ProcInstId = 0;
int ActInstId = 0;
int.TryParse(item.Properties["ProcessInstanceID"].Value, out ProcInstId);
int.TryParse(item.Properties["ActivityInstanceID"].Value, out ActInstId);
DateTime startDate = DateTime.Today;
DateTime finishDate = DateTime.Today;
DateTime.TryParse(item.Properties["StartDate"].Value, out startDate);
DateTime.TryParse(item.Properties["FinishDate"].Value, out finishDate);
list.Add(new Events
{
ProcessInstanceId = ProcInstId,
ActivityInstanceId = ActInstId,
EventName = item.Properties["EventName"].Value,
Status = item.Properties["Status"].Value,
StartDate = startDate,
FinishDate = finishDate,
Destination = item.Properties["Destination"].Value
});
}
}
catch (Exception ex)
{
list.Add(new Events
{
ProcessInstanceId = 0,
ActivityInstanceId = 0,
EventName = ex.Message,
Status = "Error",
StartDate = DateTime.Today,
FinishDate = DateTime.Today
});
}
finally
{
serverName.Connection.Close();
}
return list;
}
public void IsErrors(int processinstanceId, string workflowname)
{
}
/// <summary>
/// Gets all the activities that are in a workflow
/// </summary>
/// <param name="ProcId"></param>
/// <returns></returns>
public List<ActivityDesign> GetWorkflowActivities(int ProcId)
{
List<ActivityDesign> list = new List<ActivityDesign>();
SourceCode.Workflow.Management.WorkflowManagementServer workflowServer = new SourceCode.Workflow.Management.WorkflowManagementServer(servername, 5555);
workflowServer.Open();
try
{
foreach (SourceCode.Workflow.Management.Activity activity in workflowServer.GetProcActivities( ProcId))
{
list.Add(new ActivityDesign
{
ID = activity.ID,
Name = activity.Name,
Description = activity.Description
});
}
}
catch (Exception ex)
{
list.Add(new ActivityDesign
{
ID = 0,
Name = "Error",
Description = ex.Message
});
}
finally
{
workflowServer.Connection.Close();
}
return list;
}
/// <summary>
/// Gets a list of all the workflows
/// </summary>
/// <returns></returns>
public List<Workflow> GetProcesses()
{
List<Workflow> list = new List<Workflow>();
SourceCode.Workflow.Management.WorkflowManagementServer workflowServer = new SourceCode.Workflow.Management.WorkflowManagementServer(servername,5555);
workflowServer.Open();
try
{
SourceCode.Workflow.Management.Criteria.ProcessCriteriaFilter filter = new SourceCode.Workflow.Management.Criteria.ProcessCriteriaFilter();
SourceCode.Workflow.Management.Processes processes = workflowServer.GetProcesses(filter);
foreach (SourceCode.Workflow.Management.Process process in processes)
{
if (process.DefaultVersion == true)
{
list.Add(
new Workflow
{
ID = process.ProcID,
Name = process.FullName
}
);
}
}
}
catch (Exception ex)
{
list.Add(
new Workflow
{
ID = 0,
Name = ex.Message
}
);
}
finally
{
workflowServer.Connection.Close();
}
return list;
}
}
}
XML DataStoreResult.xml
Used to hold test data
<?xml version="1.0" encoding="utf-8" ?>
<Settings>
<ProcessName>k2-server-int02</ProcessName>
<Folio></Folio>
<ProcessInstanceId>5555</ProcessInstanceId>
<StartStatus>End</StartStatus>
<TaskCount Actual="1">0</TaskCount>
<SerialNumber>00_00</SerialNumber>
<Destination>Bob</Destination>
<Actions>
<Action>Approve</Action>
</Actions>
<ActionResult>Approve</ActionResult>
<Activities>
<Activity>
<Event name="Status Check">Pass</Event>
</Activity>
</Activities>
</Settings>
Unit Test Unittest.cs
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading;
namespace K2WorkflowUnitTest
{
[TestClass]
public class UnitTest1
{
private string folio;
private string ProcessName;
private int proceessInstance;
private string SerialNumber;
private string TaskAction;
private int TaskCount = 0;
private string Activities;
private string DestinationUser;
private string TaskActivity;
private int milliseconds;
private SourceCode.Workflow.Client.Actions Actions;
private K2WorkflowMap.WorkflowInstanceFramework workflow;
private Results Results;
public int ProcInstId { get; set; }
[TestInitialize]
public void TestInitialize()
{
this.folio = "I am a folio 3";
this.ProcessName = @"K2Project2\TestProcess";
this.TaskActivity = "Task";
this.TaskAction = "Approve";
this.Activities = "Setup;Task;Approve;End";
this.TaskCount = 1;
this.milliseconds = 3000;
workflow = new K2WorkflowMap.WorkflowInstanceFramework();
Results = new Results();
Results.SetUpXML(this.ProcessName, this.folio);
}
/// <summary>
/// Tests the starting of a workflow, should return a number greater than 0
/// </summary>
/// <param name="folio"></param>
/// <param name="ProceesName"></param>
/// <returns></returns>
[TestMethod]
public void StartWorkflow_Success()
{
int actual = workflow.StartProcess(this.folio, this.ProcessName);
this.proceessInstance = actual;
Results.SaveResult(TestType.ProcessInstance, this.proceessInstance.ToString());
Assert.AreNotEqual(0, actual);
ProcInstId = this.proceessInstance;
}
/// <summary>
/// Test to check that the workflow has started, by checking it's status
/// </summary>
/// <param name="ProcessInstanceId"></param>
[TestMethod]
public void StartWorkflow_Running_Success()
{
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
string actual = workflow.GetWorkflowStatus(this.proceessInstance);
Results.SaveResult(TestType.StartStatus, actual);
StringAssert.Equals(SourceCode.Workflow.Client.ProcessInstance.Status.Active.ToString(), actual);
}
/// <summary>
/// Tests to see if tasks have been generated for this instance
/// </summary>
[TestMethod]
public void WorkList_TasksFound_Success()
{
Thread.Sleep(milliseconds);
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
Boolean actual = false;
actual = workflow.IsTaskFound(this.proceessInstance, this.ProcessName);
Assert.AreEqual(true, actual);
}
/// <summary>
/// Checks that the correct number of tasks is generated
/// </summary>
[TestMethod]
public void WorkList_CorrectNumberOfTasksCreated_Success()
{
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
int actual = 0;
actual = workflow.GetTaskCount(this.proceessInstance, this.ProcessName);
Results.SaveResult(TestType.TaskCount, actual.ToString());
Assert.AreEqual(this.TaskCount, actual);
}
/// <summary>
/// Gets the activity name of the task
/// </summary>
[TestMethod]
public void WorkList_RetrieveTaskList_Success()
{
string Actual = string.Empty;
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
var task = workflow.GetTask(this.proceessInstance, this.ProcessName);
this.SerialNumber = task[0].SerialNumber;
Results.SaveResult(TestType.SerialNumber, this.SerialNumber);
this.DestinationUser = task[0].Destination;
Results.SaveResult(TestType.Destination, this.DestinationUser);
Actual = task[0].ActivityName;
Results.SaveResult(TestType.TaskActivity, Actual);
Assert.AreEqual(this.TaskActivity, Actual);
}
/// <summary>
/// Actions a task
/// </summary>
[TestMethod]
public void Task_GetActions_Sucess()
{
Boolean Actual = false;
this.SerialNumber = Results.GetResult(TestType.SerialNumber);
this.DestinationUser = Results.GetResult(TestType.Destination);
K2WorkflowMap.TaskDetails task = workflow.OpenTask(this.SerialNumber, this.DestinationUser)[0];
Actual = workflow.ActionTask(this.TaskAction, this.SerialNumber, this.DestinationUser);
Assert.AreEqual(true, Actual);
}
/// <summary>
/// checks to see if task is complete by checking that task has gone
/// </summary>
[TestMethod]
public void Task_CheckTaskComplete_Success()
{
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
int actual = 0;
actual = workflow.GetTaskCount(this.proceessInstance, this.ProcessName);
Results.SaveResult(TestType.TaskCount, actual.ToString());
Assert.AreEqual(0, actual);
}
/// <summary>
/// Checks the correct number of activities ran
/// </summary>
[TestMethod]
public void Activities_CompareNumberOfActivities_Success()
{
Thread.Sleep(milliseconds);
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
int NumberOfActivitiesRan = workflow.GetActivities(this.proceessInstance.ToString()).Count;
String[] activities = this.Activities.Split(';');
int count = 0;
foreach (var activity in activities)
{
count++;
}
Assert.AreEqual(count, NumberOfActivitiesRan);
}
/// <summary>
/// Checks the correct activities were executed in correct order
/// </summary>
///
[TestMethod]
public void Activities_CorrectActivitiesRan_Success()
{
Thread.Sleep(milliseconds);
int.TryParse(Results.GetResult(TestType.ProcessInstance), out this.proceessInstance);
Boolean actual = workflow.CompareActivities(this.proceessInstance, this.Activities);
Assert.IsTrue(actual);
}
}
}