blob: a48fc77aac096abfa8301abe6872b7b5c316c97c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Xml;
namespace Apache.Geode.Client.FwkLib
{
using Apache.Geode.DUnitFramework;
public class FwkTask
{
#region Private members
private Delegate m_delegate;
private Delegate m_pushTaskNameDelegate;
private Delegate m_endDelegate;
private List<string> m_clients;
private TimeBomb m_timeBomb;
private string m_class;
private int m_timeoutMillis;
private int m_timesToRun;
private int m_threadCount;
private bool m_parallel;
private bool m_continueOnError;
private ClientGroup m_clientGroup;
private List<string> m_localDataNames;
private UnitFnMethod<FwkTask, ClientBase> m_taskStartedHandler;
private UnitFnMethod<FwkTask, ClientBase, Exception> m_taskDoneHandler;
private bool m_taskStatus;
#endregion
#region Private constants and static members
private const string PushTaskNameMethod = "PushTaskName";
private const string EndTaskMethod = "EndTask";
private const int DefaultTimeoutMillis = 600000;
private static string[] ThreadCountKeys = { "threadCount", "numThreads" };
private static Dictionary<string, int> m_GlobalTaskNames =
new Dictionary<string, int>();
private static Dictionary<string, Assembly> m_AssemblyMap =
new Dictionary<string, Assembly>();
private const string ClientCountKey = "clientCount";
private const string NameAttrib = "name";
private const string MethodAttrib = "action";
private const string ClassAttrib = "class";
private const string ContainerAttrib = "container";
private const string WaitTimeAttrib = "waitTime";
private const string TimesToRunAttrib = "timesToRun";
private const string ThreadCountAttrib = "threadCount";
private const string ParallelAttrib = "parallel";
private const string ContinueAttrib = "continueOnError";
private const string ArgTypes = "argTypes";
#endregion
#region Public accessors
public static Dictionary<string, int> GlobalTaskNames
{
get
{
return m_GlobalTaskNames;
}
}
public List<string> ClientNames
{
get
{
return m_clients;
}
}
public string Name
{
get
{
return (m_timeBomb == null ? null : m_timeBomb.TaskName);
}
}
public string Class
{
get
{
return m_class;
}
}
public int Timeout
{
get
{
return m_timeoutMillis;
}
}
public int TimesToRun
{
get
{
return m_timesToRun;
}
}
public int ThreadCount
{
get
{
return m_threadCount;
}
}
public bool Parallel
{
get
{
return m_parallel;
}
}
public bool ContinueOnError
{
get
{
return m_continueOnError;
}
}
#endregion
#region Private methods
private void HandleTaskStarted(ClientBase client)
{
if (m_taskStartedHandler != null)
{
m_taskStartedHandler(this, client);
}
}
private void HandleTaskDone(ClientBase client, Exception ex)
{
if (m_taskDoneHandler != null)
{
m_taskStatus = (ex == null);
m_taskDoneHandler(this, client, ex);
}
}
#endregion
#region Public methods
public FwkTask(XmlNode node, string testName,
UnitFnMethod<FwkTask, ClientBase> taskStartedHandler,
UnitFnMethod<FwkTask, ClientBase, Exception> taskDoneHandler)
{
if (node == null)
{
throw new IllegalArgException("Null node for FwkTask constructor.");
}
#region Read the attributes
string taskName = string.Empty;
string containerStr = null;
string methodName = null;
string typeAttrib = null;
m_timesToRun = 1;
m_threadCount = 1;
m_parallel = false;
m_timeoutMillis = DefaultTimeoutMillis;
m_continueOnError = false;
m_class = null;
XmlAttributeCollection xmlAttribs = node.Attributes;
if (xmlAttribs != null)
{
foreach (XmlAttribute xmlAttrib in xmlAttribs)
{
switch (xmlAttrib.Name)
{
case NameAttrib:
taskName = xmlAttrib.Value;
break;
case ArgTypes:
typeAttrib = xmlAttrib.Value;
break;
case ContainerAttrib:
containerStr = xmlAttrib.Value;
break;
case MethodAttrib:
methodName = xmlAttrib.Value;
break;
case TimesToRunAttrib:
m_timesToRun = XmlNodeReaderWriter.String2Int(xmlAttrib.Value, 1);
break;
case ThreadCountAttrib:
m_threadCount = XmlNodeReaderWriter.String2Int(xmlAttrib.Value, 1);
break;
case ParallelAttrib:
m_parallel = XmlNodeReaderWriter.String2Bool(xmlAttrib.Value, false);
break;
case WaitTimeAttrib:
m_timeoutMillis = XmlNodeReaderWriter.String2Seconds(xmlAttrib.Value,
DefaultTimeoutMillis) * 1000;
break;
case ContinueAttrib:
m_continueOnError = XmlNodeReaderWriter.String2Bool(xmlAttrib.Value, false);
break;
case ClassAttrib:
m_class = xmlAttrib.Value;
break;
default:
throw new IllegalArgException("Unknown attribute '" +
xmlAttrib.Name + "' found in '" + node.Name +
"' node.");
}
}
}
int taskNum = 1;
if (m_GlobalTaskNames.ContainsKey(taskName))
{
taskNum = m_GlobalTaskNames[taskName] + 1;
}
m_GlobalTaskNames[taskName] = taskNum;
taskName += '_' + taskNum.ToString();
#endregion
m_timeBomb = new TimeBomb();
m_timeBomb.TaskName = testName + '.' + taskName;
#region Create a delegate by loading the assembly
Assembly loadAssmb = null;
string typeName = null;
if (containerStr != null && methodName != null)
{
object inst = null;
int dotIndx;
if ((dotIndx = containerStr.IndexOf('.')) < 0)
{
Type myType = this.GetType();
loadAssmb = myType.Assembly;
typeName = myType.Namespace + '.' + containerStr;
Util.Log(Util.LogLevel.Info, "Assembly {0} loaded and typename is {1}", loadAssmb, typeName);
}
else
{
string assmbName = containerStr.Substring(0, dotIndx);
if (!m_AssemblyMap.TryGetValue(assmbName, out loadAssmb))
{
try
{
loadAssmb = Assembly.Load(assmbName);
Util.Log(Util.LogLevel.Info, "Assembly {0} loaded ", assmbName);
}
catch (Exception e)
{
throw new IllegalArgException("Cannot load assembly '" +
assmbName + "' for task: " + m_timeBomb.TaskName +
" exception: " + e);
}
m_AssemblyMap.Add(assmbName, loadAssmb);
}
typeName = containerStr.Substring(dotIndx + 1);
}
//string typeAttrib;
if (loadAssmb != null)
{
if (typeAttrib == null)
{
inst = loadAssmb.CreateInstance(typeName, true);
}
else
{
//typeAttrib = "Apache.Geode.Client.Tests.ArrayOfByte,Apache.Geode.Client.Tests.ArrayOfByte";
//typeAttrib = "System.int,System.Int32";
string[] typeNames = typeAttrib.Split(',');
string mangledName = typeName + "`" + typeNames.Length.ToString();
//Type type = loadAssmb.GetType(mangledName, true, true);
Type[] types = new Type[typeNames.Length];
for (int index = 0; index < typeNames.Length; ++index)
{
string typName = typeNames[index].Trim();
if (typName == "int" || typName == "Int32" || typName == "string" ||
typName == "String" || typName == "byte[]" || typName == "Byte[]"
|| typName == "string[]" || typName == "String[]" || typName == "Object"
|| typName == "object")
{
if (typName.Equals("int"))
typName = "Int32";
else if (typName.Equals("string"))
typName = "String";
else if (typName.Equals("string[]"))
typName = "String[]";
else if (typName.Equals("byte[]"))
typName = "Byte[]";
else if (typName.Equals("object"))
typName = "Object";
typName = "System." + typName;
//Util.Log("rjk: FwkTask: typeAttrib 33 argname {0}", typName);
types[index] = Type.GetType(typName.Trim());
//Util.Log("rjk: FwkTask: typeAttrib 34 argname {0}", typName);
}
else
{
typName = "Apache.Geode.Client.Tests." + typName;
types[index] = loadAssmb.GetType(typName.Trim(), true, true);
//Util.Log("rjk: FwkTask: typeAttrib for userobject 34 argname {0}", typName);
}
}
Type type = loadAssmb.GetType(mangledName, true, true).MakeGenericType(types);
inst = type.GetConstructor(System.Type.EmptyTypes).Invoke(null);
}
}
if (inst != null)
{
try
{
MethodInfo mInfo = inst.GetType().GetMethod(methodName,
BindingFlags.IgnoreCase | BindingFlags.Public |
BindingFlags.Static | BindingFlags.FlattenHierarchy |
BindingFlags.Instance);
m_delegate = Delegate.CreateDelegate(typeof(UnitFnMethod), inst,
mInfo, true);
}
catch (Exception ex)
{
throw new IllegalArgException(
"Exception while creating delegate [" + methodName + "]: " + ex);
}
m_pushTaskNameDelegate = Delegate.CreateDelegate(
typeof(UnitFnMethod<string>), inst, PushTaskNameMethod, true);
m_endDelegate = Delegate.CreateDelegate(
typeof(UnitFnMethod), inst, EndTaskMethod, true);
}
}
if (m_delegate == null)
{
throw new IllegalArgException("Cannot create delegate '" +
methodName + "' for task: " + m_timeBomb.TaskName);
}
#endregion
#region Add the clients
m_clients = new List<string>();
m_clientGroup = new ClientGroup(false);
m_clients = FwkClient.ReadClientNames(node, false);
List<ClientBase> clients = FwkClient.GetClients(m_clients);
m_clientGroup.Add(clients);
m_timeBomb.AddClients(new ClientBase[] { m_clientGroup });
m_taskStartedHandler = taskStartedHandler;
m_taskDoneHandler = taskDoneHandler;
int clientCount = m_clients.Count;
#endregion
#region Add any data
m_localDataNames = new List<string>();
Dictionary<string, FwkData> data = FwkData.ReadDataNodes(node);
// Task specific data is written as <taskname>.<key> to avoid
// overwriting the global data, since that needs to be preserved
// across tasks.
if (m_threadCount > 1)
{
// We shall treat 'threadCount' and 'numThreads' as equivalent,
// i.e. if 'threadCount' is defined for a task then 'numThreads'
// shall also be written as data.
foreach (string threadKey in ThreadCountKeys)
{
m_localDataNames.Add(threadKey);
Util.BBSet(Name, threadKey,
new FwkData(m_threadCount.ToString(), null, DataKind.String));
}
}
if (clientCount > 0)
{
// Overwrite the clientCount (if any) with the actual value.
Util.BBSet(Name, ClientCountKey,
new FwkData(clientCount.ToString(), null, DataKind.String));
}
foreach (KeyValuePair<string, FwkData> pair in data)
{
m_localDataNames.Add(pair.Key);
Util.BBSet(Name, pair.Key, pair.Value);
}
#endregion
}
public void AddClients(params ClientBase[] clients)
{
m_clientGroup.Add(clients);
}
public void SetClients(params ClientBase[] clients)
{
m_clientGroup.Clients.Clear();
m_clientGroup.Add(clients);
}
public bool Execute()
{
m_taskStatus = true;
m_timeBomb.Start(m_timeoutMillis);
try
{
if (m_pushTaskNameDelegate != null)
{
m_clientGroup.CallFn(m_pushTaskNameDelegate,
new object[] { m_timeBomb.TaskName });
}
if (m_taskStartedHandler != null || m_taskDoneHandler != null)
{
m_clientGroup.AddTaskHandlers(HandleTaskStarted, HandleTaskDone);
}
FwkReadData read = new FwkReadData();
read.PushTaskName(Name);
string appDomain = read.GetStringValue("appdomain");
if (appDomain != null && appDomain.Length > 0) {
m_clientGroup.CallFn(m_delegate, new object[] { Util.AppDomainPrefix
+ appDomain });
}
else {
m_clientGroup.CallFn(m_delegate, null);
}
if (m_taskStartedHandler != null || m_taskDoneHandler != null)
{
m_clientGroup.RemoveTaskHandlers(HandleTaskStarted, HandleTaskDone);
}
}
finally
{
m_timeBomb.Diffuse();
}
return m_taskStatus;
}
public void ClearData()
{
foreach (string dataName in m_localDataNames)
{
Util.BBRemove(Name, dataName);
}
}
public void EndTask()
{
if (m_endDelegate != null)
{
m_clientGroup.CallFn(m_endDelegate, null);
}
m_clientGroup.RemoveObject(m_delegate.Target);
}
public void SetLogFile(string logPath)
{
m_clientGroup.SetNameLogFile(logPath);
}
public void SetLogLevel(Util.LogLevel logLevel)
{
m_clientGroup.SetLogLevel(logLevel);
}
public string Dump()
{
StringBuilder dumpStr = new StringBuilder();
dumpStr.Append(Environment.NewLine + "The task name is: " +
m_timeBomb.TaskName);
dumpStr.Append(string.Format("{0}The function to be executed: " +
"'{1}' in class '{2}'", Environment.NewLine, m_delegate.Method.Name,
m_delegate.Method.ReflectedType.FullName));
dumpStr.Append(Environment.NewLine + "The class of the task: " +
m_class);
dumpStr.Append(Environment.NewLine + "The threadCount is: " +
m_threadCount);
dumpStr.Append(Environment.NewLine + "Parallel attribute is: " +
m_parallel);
dumpStr.Append(Environment.NewLine + "Times to run is: " +
m_timesToRun);
dumpStr.Append(Environment.NewLine + "The clients are: ");
foreach (string clientName in m_clients)
{
dumpStr.Append(Environment.NewLine + "\t" + clientName);
}
dumpStr.Append(Environment.NewLine + "Continue on error is: " +
m_continueOnError);
dumpStr.Append(Environment.NewLine + "The local data names are: ");
foreach (string dataName in m_localDataNames)
{
dumpStr.Append(Environment.NewLine + '\t' + dataName);
}
dumpStr.Append(Environment.NewLine + "The timeout is: " +
m_timeoutMillis);
return dumpStr.ToString();
}
#endregion
}
}