Connection was forcibly closed by the remote host on receive - unit-testing

Hello i am trying to understand why i am getting this exception:
Message: System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host
I am performing unit tests using NUnit and i am using the same redis-server instance for all of the tests (hosted on local).
The first unit test set works like a charm - i can send and receive data from the Redis server.
On the second test i can send but on receive i get the exception thrown.Do i have to close the socket between tests (given it is not disposed when out of test-scope) or is there something i must be aware of when switching from a unit test to another?
Test that works
class RedisTests
{
[TestCase("*2\r\n$3\r\nget\r\n$1\r\na\r\n","$1\r\n3\r\n")]
[TestCase("*3\r\n$3\r\nset\r\n$1\r\na\r\n$1\r\n3\r\n", "+OK\r\n",Description ="Cmd:Set a 3 Result: +OK\r\n")]
public async Task RedisSetTest(string command, string expectedResult)
{
Socket socket = TConstants.MakeSocket();
IPEndPoint redisPoint = TConstants.MakeEndpoint(TConstants.DEFAULT_ADDRESS,TConstants.REDIS_PORT);
await socket.ConnectAsync(redisPoint);
Provider provider = Provider.Create(socket, 30);
await socket.SendAsync(TConstants.UTF8Encode(command), SocketFlags.None);
try
{
SmartMemory memory = await provider.ReceiveAsync();
var payload = Extensions.Map(x => (char)x,
memory.Iterator.Slice(0, memory.Message.Length).ToEnumerable()
);
string result = string.Concat(payload);
Assert.AreEqual(expectedResult, result);
}
catch (Exception exception)
{
Debug.WriteLine(exception.Message);
throw;
}
}
}
P.S The Provider's method ReceiveAsync is just a wrapper and performs the Socket.ReceiveAsync at its core the same way.
Test that throws exception
class STMTests
{
[TestCase(2)]
public async Task FillIntegerNode(int value)
{
Socket socket = TConstants.MakeSocket();
IPEndPoint redisPoint=TConstants.MakeEndpoint(TConstants.DEFAULT_ADDRESS, TConstants.REDIS_PORT);
//port = 6379
//address="127.0.0.1"
await socket.ConnectAsync(redisPoint);
Memory<byte>data=BitConverter.GetBytes(injectableNode.Value);
int sent=await socket.SendAsync(data, SocketFlags.None);
Memory<byte> dt = new byte[33];
var mem = await socket.ReceiveAsync(dt, SocketFlags.None);
Assert.IsTrue(true);
}
}
I added a picture with the test hierachy :

It's a general rule that if you create something disposable, then you are the one responsible for disposing of it. In this case, you are creating the socket in each test, right in the test method itself. So you have to dispose it in the test method or in a TearDown, which is run immediately after each test method.
Generally, the simplest way to dispose of something created in a test is via using.
OTOH, if you wanted all the methods in the test fixture class to use the same socket, you should open it in a OneTimeSetUp method and dispose it in a OneTimeTearDown.

Related

Data is not reaching to the websocket clients in AWS API Gateway websocket

I have created an lambda function to which I am not able to send the data to the web socket clients. However there is NO error is coming.
Till yesterday code was working. Dont know what happend now it stopped working.
public string FunctionHandler(string input, ILambdaContext context)
{
try
{
string SK = "xxxxxx";
string AK = "xxxx";
var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(input));
var apiClient = new AmazonApiGatewayManagementApiClient(AK,SK,new AmazonApiGatewayManagementApiConfig
{ ServiceURL = $"https://xxxxxx.execute-api.us-east-1.amazonaws.com/Test" });
apiClient.PostToConnectionAsync(new Amazon.ApiGatewayManagementApi.Model.PostToConnectionRequest
{
ConnectionId = "​fdCqPfd0oAMCJmg=",
Data = stream
});
return input.ToUpper();
}
catch(Exception ex)
{
return ex.ToString();
}
}
I gather you're using .NET AmazonApiGatewayManagementApiClient. You're missing the await keyword for apiClient.PostToConnectionAsync():
await apiClient.PostToConnectionAsync(...);
Otherwise you're calling PostToConnectionAsync() without waiting for completion and your Lambda might complete and exit before your request is run and you'll never know about it. (See asynchronous concepts for details)
Alternatively, don't use async method:
apiClient.PostToConnection(...);

Azure Webjob, KeyVault Configuration extension, Socket Error

Need some help to determine if this is a bug in my code or in the config kevault extensions.
I have a netcore console based webjob. all working fine until a few weeks ago when we stated getting occasional startup errors which were Socket Error 10060 - Socket timed out or "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond"
These were all related to loading configuration layers (app settings, env, command line and keyvault). The errors stemmed from the keyvault once the build was executed on the hostbuilder.
I initially added the retry policy with the default HttpStatusCodeErrorDetectionStrategy and an exponential back-off but this is not executing.
finally I added my own retry policy with my own detection strategy (see below). Still not being fired.
I have stripped down the code to a hello world like example and included the messages from the webjob.
Here is the code summary:
Main
public static async Task<int> Main(string[] args)
{
var host = CreateHostBuilder(args)
.UseConsoleLifetime()
.Build();
using var serviceScope = host.Services.CreateScope();
var services = serviceScope.ServiceProvider;
//**stripped down to logging just for debug
var loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Main");
logger.LogDebug("Hello Test App Started OK. Exiting.");
//**Normally lots of service calls go here to do real work**
return 0;
}
HostBuilder - why hostbuilder? We use lots of components that are built for webapi and webapps so it was convenient to use a similar services model.
public static IHostBuilder CreateHostBuilder(string[] args)
{
var host = Host
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((ctx, config) =>
{
//override with keyvault
var azureServiceTokenProvider = new AzureServiceTokenProvider(); //this is awesome - it will use MSI or Visual Studio connection
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var retryPolicy = new RetryPolicy<ServerErrorDetectionStrategy>(
new ExponentialBackoffRetryStrategy(
retryCount: 5,
minBackoff: TimeSpan.FromSeconds(1.0),
maxBackoff: TimeSpan.FromSeconds(16.0),
deltaBackoff: TimeSpan.FromSeconds(2.0)
)
);
retryPolicy.Retrying += RetryPolicy_Retrying;
keyVaultClient.SetRetryPolicy(retryPolicy);
var prebuiltConfig = config.Build();
config.AddAzureKeyVault(prebuiltConfig.GetSection("KeyVaultSettings").GetValue<string>("KeyVaultUri"), keyVaultClient, new DefaultKeyVaultSecretManager());
config.AddCommandLine(args);
})
.ConfigureLogging((ctx, loggingBuilder) => //note - this is run AFTER app configuration - whatever the order it is in.
{
loggingBuilder.ClearProviders();
loggingBuilder
.AddConsole()
.AddDebug()
.AddApplicationInsightsWebJobs(config => config.InstrumentationKey = ctx.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"]);
})
.ConfigureServices((ctx, services) =>
{
services
.AddApplicationInsightsTelemetry();
services
.AddOptions();
});
return host;
}
Event - this is never fired.
private static void RetryPolicy_Retrying(object sender, RetryingEventArgs e)
{
Console.WriteLine($"Retrying, count = {e.CurrentRetryCount}, Last Exception={e.LastException}, Delay={e.Delay}");
}
Retry Policy - only fires for the non-MSI attempt to contact the keyvault.
public class ServerErrorDetectionStrategy : ITransientErrorDetectionStrategy
{
public bool IsTransient(Exception ex)
{
if (ex != null)
{
Console.WriteLine($"Exception {ex.Message} received, {ex.GetType()?.FullName}");
HttpRequestWithStatusException httpException;
if ((httpException = ex as HttpRequestWithStatusException) != null)
{
switch(httpException.StatusCode)
{
case HttpStatusCode.RequestTimeout:
case HttpStatusCode.GatewayTimeout:
case HttpStatusCode.InternalServerError:
case HttpStatusCode.ServiceUnavailable:
return true;
}
}
SocketException socketException;
if((socketException = (ex as SocketException)) != null)
{
Console.WriteLine($"Exception {socketException.Message} received, Error Code: {socketException.ErrorCode}, SocketErrorCode: {socketException.SocketErrorCode}");
if (socketException.SocketErrorCode == SocketError.TimedOut)
{
return true;
}
}
}
return false;
}
}
WebJob Output
[SYS INFO] Status changed to Initializing
[SYS INFO] Run script 'run.cmd' with script host - 'WindowsScriptHost'
[SYS INFO] Status changed to Running
[INFO]
[INFO] D:\local\Temp\jobs\triggered\HelloWebJob\42wj5ipx.ukj>dotnet HelloWebJob.dll
[INFO] Exception Response status code indicates server error: 401 (Unauthorized). received, Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException
[INFO] Exception A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. received, System.Net.Http.HttpRequestException
[ERR ] Unhandled exception. System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
[ERR ] ---> System.Net.Sockets.SocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
[ERR ] at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
[ERR ] --- End of inner exception stack trace ---
[ERR ] at Microsoft.Rest.RetryDelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
[ERR ] at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
[ERR ] at Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretWithHttpMessagesAsync(String vaultBaseUrl, String secretName, String secretVersion, Dictionary`2 customHeaders, CancellationToken cancellationToken)
[ERR ] at Microsoft.Azure.KeyVault.KeyVaultClientExtensions.GetSecretAsync(IKeyVaultClient operations, String secretIdentifier, CancellationToken cancellationToken)
[ERR ] at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.LoadAsync()
[ERR ] at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.Load()
[ERR ] at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
[ERR ] at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
[ERR ] at Microsoft.Extensions.Hosting.HostBuilder.BuildAppConfiguration()
[ERR ] at Microsoft.Extensions.Hosting.HostBuilder.Build()
[ERR ] at HelloWebJob.Program.Main(String[] args) in C:\Users\mark\Source\Repos\HelloWebJob\HelloWebJob\Program.cs:line 21
[ERR ] at HelloWebJob.Program.<Main>(String[] args)
[SYS INFO] Status changed to Failed
[SYS ERR ] Job failed due to exit code -532462766
This is an issue in the KV connectivity which is identified by the PG. Below is an official statement from Product Group:
The Microsoft Azure App Service Team has identified an issue with the
Key Vault references for App Service and Azure Functions feature
related to intermittent failure to resolve references at runtime.
Engineers identified a regression in the system that reduced the
performance and availability of our scale unit’s ability to retrieve
key vault references at runtime. A patch has been written and deployed
to our fleet of VMs to mitigate this issue.
We are continuously taking steps to improve the Azure Web App service
and our processes to ensure such incidents do not occur in the future,
and in this case, it includes (but is not limited to): Improving
detection and testing of performance and availability of the Key Vault
App Setting References feature Improvements to our platform to ensure
high availability of this feature at runtime. We apologize for any
inconvenience.
For almost everyone, updating packages to the new Microsoft.Azure packages has mitigated this issue, so trying those would be my first suggestion.
Thanks #HarshitaSingh-MSFT, makes sense though I searched for this when I had the problem and couldn't find it.
As a work around, I added some basic retry code to the startup.
Main looks like this for now:
public static async Task<int> Main(string[] args)
{
IHost host = null;
int retries = 5;
while (true)
{
try
{
Console.WriteLine("Building Host...");
var hostBuilder = CreateHostBuilder(args)
.UseConsoleLifetime();
host = hostBuilder.Build();
break;
}
catch (HttpRequestException hEx)
{
Console.WriteLine($"HTTP Exception in host builder. {hEx.Message}, Name:{hEx.GetType().Name}");
SocketException se;
if ((se = hEx.InnerException as SocketException) != null)
{
if (se.SocketErrorCode == SocketError.TimedOut)
{
Console.WriteLine($"Socket error in host builder. Retrying...");
if (retries > 0)
{
retries--;
await Task.Delay(5000);
host?.Dispose();
}
else
{
throw;
}
}
else
{
throw;
}
}
}
}
using var serviceScope = host.Services.CreateScope();
var services = serviceScope.ServiceProvider;
var transferService = services.GetRequiredService<IRunPinTransfer>();
var result = await transferService.ProcessAsync();
return result;
}

How to I unit test a #future method that uses a callout?

I have a trigger that fires when an opportunity is updated, as part of that I need to call our API with some detail from the opportunity.
As per many suggestions on the web I've created a class that contains a #future method to make the callout.
I'm trying to catch an exception that gets thrown in the #future method, but the test method isn't seeing it.
The class under test looks like this:
public with sharing class WDAPIInterface {
public WDAPIInterface() {
}
#future(callout=true) public static void send(String endpoint, String method, String body) {
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod(method);
req.setBody(body);
Http http = new Http();
HttpResponse response = http.send(req);
if(response.getStatusCode() != 201) {
System.debug('Unexpected response from web service, expecte response status status 201 but got ' + response.getStatusCode());
throw new WDAPIException('Unexpected response from web service, expecte response status status 201 but got ' + response.getStatusCode());
}
}
}
here's the unit test:
#isTest static void test_exception_is_thrown_on_unexpected_response() {
try {
WDHttpCalloutMock mockResponse = new WDHttpCalloutMock(500, 'Complete', '', null);
WDAPIInterface.send('https://example.com', 'POST', '{}');
} catch (WDAPIException ex) {
return;
}
System.assert(false, 'Expected WDAPIException to be thrown, but it wasnt');
}
Now, I've read that the way to test #future methods is to surround the call with Test.startTest() & Test.endTest(), however when I do that I get another error:
METHOD RESULT
test_exception_is_thrown_on_unexpected_response : Skip
MESSAGE
Methods defined as TestMethod do not support Web service callouts, test skipped
So the question is, how do I unit test a #future method that makes an callout?
The callout is getting skipped because the HttpCalloutMock isn't being used.
I assume that WDHttpCalloutMock implements HttpCalloutMock?
If so, a call to Test.setMock should have it return the mocked response to the callout.
WDHttpCalloutMock mockResponse = new WDHttpCalloutMock(500, 'Complete', '', null);
Test.setMock(HttpCalloutMock.class, mockResponse);
WDAPIInterface.send('https://example.com', 'POST', '{}');
Incidentally, the Salesforce StackExchange site is a great place to ask Salesforce specific questions.

Calling WebAPI in UnitTest TestInitialize

im trying to write a UnitTest for a WebAPI and EF
Im trying to add Data do the database in den TestInitialize, but it didnt work. When i do the same command in a Console Applications, it works.
Is there a different in calling that webapi for tests?
[TestInitialize]
public void CreateEntityObjects()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:60609/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Department dep1 = new Department() { Id = Guid.NewGuid(), Name = "IT" };
client.PostAsJsonAsync("api/Department", dep1);
}
Edit:
So i still just do the initialize no cleanup (later). I was looking manually if there is some data in the database. But no data, no Error, nothing.
You may try looking at the result property of the request:
var response = client.PostAsJsonAsync("api/Department", dep1).Result;
and then look at what does the server return:
string responseContent = response.Result.Content.ReadAsStringAsync().Result;
Now analyze the responseContent variable to see what possible error message you might have gotten from the server. Also you probably want to self-host your Web API in the unit test before sending an HTTP request to it, otherwise your API might not even be started.

Resteasy, Make a Http-Put or Http-Post with Server-side Mock Framework of RestEasy

I wrote a Rest-Service which i would like to test.
I wanna run a JUnit test without having my server run. For this I am using the Server-side Mock Framework of RestEasy.
My question is, how can I make a Http-Put or Http-Post request with this framework with an marshalled Java Object in the Http-Body???
The Code below runs fine for an Http-Get, but how to make a Put or Post, maybe someone got some example code for this???
#Test
public void testClient() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(
MyClass.class);
dispatcher.getRegistry().addResourceFactory(noDefaults);
{
MockHttpRequest request = MockHttpRequest.get("/message/test/"
+ requestParam);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
}
}
A bit late response but , might have some use for someone.
This is how i usually test my PUT requests. Hope it helps
#Test
public void testPUT() throws Exception {
POJOResourceFactory noDefaults = new POJOResourceFactory(REST.class);
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addResourceFactory(noDefaults);
String url = "your_url_here";
MockHttpRequest request = MockHttpRequest.put(url);
request.accept(MediaType.APPLICATION_JSON);
request.contentType(MediaType.APPLICATION_JSON_TYPE);
// res being your resource object
request.content(res.toJSONString().getBytes());
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assert.assertEquals( HttpStatus.SC_CREATED,response.getStatus());
}