private bool Call(CallMethodRequestCollection methodsToCall)
{
Opc.Ua.Test.DataComparer comparer = new Opc.Ua.Test.DataComparer(Session.MessageContext);
bool success = true;
CallMethodResultCollection results = null;
DiagnosticInfoCollection diagnosticInfos = null;
RequestHeader requestHeader = new RequestHeader();
requestHeader.ReturnDiagnostics = 0;
try
{
Session.Call(
requestHeader,
methodsToCall,
out results,
out diagnosticInfos);
}
catch (System.ServiceModel.CommunicationException e)
{
Log("WARNING: Communication error (random data may have resulted in a message that is too large). {0}", e.Message);
return true;
}
catch (System.Xml.XmlException e)
{
Log("WARNING: XML parsing error (random data may have resulted in a message that is too large). {0}", e.Message);
return true;
}
catch (ServiceResultException e)
{
if (e.StatusCode == StatusCodes.BadEncodingLimitsExceeded)
{
Log("WARNING: Communication error (random data may have resulted in a message that is too large). {0}", e.Message);
return true;
}
throw new ServiceResultException(new ServiceResult(e));
}
ClientBase.ValidateResponse(results, methodsToCall);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, methodsToCall);
// check diagnostics.
if (diagnosticInfos != null && diagnosticInfos.Count > 0)
{
Log("Returned non-empty DiagnosticInfos array during Call.");
return false;
}
// check results.
for (int ii = 0; ii < methodsToCall.Count; ii++)
{
CallMethodRequest request = methodsToCall[ii];
TestMethod method = (TestMethod)request.Handle;
if (request.ObjectId != method.Parent.NodeId)
{
if (results[ii].StatusCode != StatusCodes.BadMethodInvalid)
{
Log(
"Invalid result when method called on wrong object '{0}'. NodeId = {1}, Method = {2}, StatusCode = {3}",
method.Parent,
method.Parent.NodeId,
method.Method,
results[ii].StatusCode);
success = false;
break;
}
continue;
}
if (results[ii].StatusCode == StatusCodes.BadUserAccessDenied)
{
if (method.Method.UserExecutable)
{
Log(
"Call failed when calling an executable method '{0}'. NodeId = {1}, Method = {2}, StatusCode = {3}",
method.Parent,
method.Parent.NodeId,
method.Method,
results[ii].StatusCode);
success = false;
break;
}
continue;
}
if (results[ii].StatusCode == StatusCodes.BadNotImplemented)
{
continue;
}
if (request.InputArguments.Count != method.InputArguments.Count)
{
if (results[ii].StatusCode != StatusCodes.BadArgumentsMissing)
{
Log(
"Incorrect error returned when passing method wrong number of arguments '{0}'. NodeId = {1}, Method = {2}, StatusCode = {3}",
method.Parent,
method.Parent.NodeId,
method.Method,
results[ii].StatusCode);
success = false;
break;
}
continue;
}
if (results[ii].StatusCode == StatusCodes.BadInvalidArgument || results[ii].StatusCode == StatusCodes.BadOutOfRange)
{
if (results[ii].InputArgumentResults.Count != request.InputArguments.Count)
{
Log(
"Incorrect number of result returned when reporting argument error '{0}'. NodeId = {1}, Method = {2}, Expected = {3}, Actual = {4}",
method.Parent,
method.Parent.NodeId,
method.Method,
request.InputArguments.Count,
results[ii].InputArgumentResults.Count);
success = false;
break;
}
bool errorFound = false;
for (int jj = 0; jj < method.InputArguments.Count; jj++)
{
if (results[ii].InputArgumentResults[jj] != results[ii].StatusCode)
{
errorFound = true;
}
Argument argument = method.InputArguments[jj];
// check if data type matches.
TypeInfo typeInfo = TypeInfo.IsInstanceOfDataType(
request.InputArguments[jj].Value,
argument.DataType,
argument.ValueRank,
Session.NamespaceUris,
Session.TypeTree);
if (typeInfo == null)
{
if (results[ii].InputArgumentResults[jj] != StatusCodes.BadTypeMismatch)
{
Log(
"Incorrect error returned for invalid argument '{0}'. NodeId = {1}, Method = {2}, Argument = {3}, StatusCode = {4}",
method.Parent,
method.Parent.NodeId,
method.Method,
method.InputArguments[jj].Name,
results[ii].InputArgumentResults[jj]);
success = false;
}
continue;
}
if (results[ii].InputArgumentResults[jj] != StatusCodes.Good && results[ii].InputArgumentResults[jj] != StatusCodes.BadOutOfRange)
{
Log(
"Incorrect error returned for valid argument '{0}'. NodeId = {1}, Method = {2}, Argument = {3}, StatusCode = {4}",
method.Parent,
method.Parent.NodeId,
method.Method,
method.InputArguments[jj].Name,
results[ii].InputArgumentResults[jj]);
success = false;
}
}
if (!success)
{
break;
}
if (!errorFound)
{
Log(
"No matching argument level error for method '{0}'. NodeId = {1}, Method = {2}, StatusCode = {4}",
method.Parent,
method.Parent.NodeId,
method.Method,
results[ii].StatusCode);
success = false;
break;
}
continue;
}
if (StatusCode.IsBad(results[ii].StatusCode))
{
if (results[ii].StatusCode != StatusCodes.BadNotImplemented)
{
Log(
"Unexpected error when calling method '{0}'. NodeId = {1}, Method = {2}, StatusCode = {3}",
method.Parent,
method.Parent.NodeId,
method.Method,
results[ii].StatusCode);
success = false;
break;
}
continue;
}
if (results[ii].OutputArguments.Count != method.OutputArguments.Count)
{
Log(
"Incorrect number of output arguments '{0}'. NodeId = {1}, Method = {2}, Expected = {3}, Actual = {4}",
method.Parent,
method.Parent.NodeId,
method.Method,
method.OutputArguments.Count,
results[ii].OutputArguments.Count);
success = false;
break;
}
for (int jj = 0; jj < method.OutputArguments.Count; jj++)
{
Argument argument = method.OutputArguments[jj];
// check if data type matches.
TypeInfo typeInfo = TypeInfo.IsInstanceOfDataType(
results[ii].OutputArguments[jj].Value,
argument.DataType,
argument.ValueRank,
Session.NamespaceUris,
Session.TypeTree);
if (typeInfo == null)
{
Log(
"Datatype for output argument is invalid '{0}'. NodeId = {1}, Method = {2}, Argument = {3}, Value = {4}",
method.Parent,
method.Parent.NodeId,
method.Method,
method.OutputArguments[jj].Name,
results[ii].OutputArguments[jj]);
success = false;
continue;
}
// check for special test methods that return the input parameters.
if (method.Parent.BrowseName.Name == "MethodTest")
{
if (jj < request.InputArguments.Count)
{
if (!comparer.CompareVariant(request.InputArguments[jj], results[ii].OutputArguments[jj]))
{
Log(
"Output argument did not match input '{0}'. NodeId = {1}, Method = {2}, Argument = {3}, Value = {4}, Output = {5}",
method.Parent,
method.Parent.NodeId,
method.Method,
method.OutputArguments[jj].Name,
request.InputArguments[jj],
results[ii].OutputArguments[jj]);
success = false;
continue;
}
}
}
}
if (!success)
{
break;
}
}
return success;
}