Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add dke:ping #138

Merged
merged 9 commits into from
Aug 20, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public static class TechnicalMessageTypes
/// </summary>
public static string DkeSubscription => "dke:subscription";

/// <summary>
/// Type 'dke:ping'.
/// </summary>
public static string DkePing => "dke:ping";

/// <summary>
/// Type 'dke:cloud_onboard_endpoints'.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Agrirouter.Api.Service.Parameters;

namespace Agrirouter.Api.Service.Messaging
{
/// <summary>
/// Send a ping message to check if the endpoint still exists.
/// </summary>
public interface IPingService : IMessagingService<PingParameters>, IEncodeMessageService<PingParameters>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Agrirouter.Api.Service.Parameters
{
public class PingParameters : MessageParameters
{
// no additional fields, but more verbosity with explicit class definition
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Agrirouter.Api.Definitions;
using Agrirouter.Api.Dto.Messaging;
using Agrirouter.Api.Service.Messaging;
using Agrirouter.Api.Service.Parameters;
using Agrirouter.Impl.Service.Common;
using Agrirouter.Request;
using Google.Protobuf;

namespace Agrirouter.Impl.Service.Messaging
{
/// <summary>
/// Service to list the endpoints connected to an endpoint.
/// </summary>
public class PingService: IPingService
{
private readonly IMessagingService<MessagingParameters> _messagingService;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="messagingService"></param>
public PingService(IMessagingService<MessagingParameters> messagingService)
{
_messagingService = messagingService;
}

/// <summary>
/// Please see base class declaration for documentation.
/// </summary>
/// <param name="pingParameters">-</param>
/// <returns>-</returns>
public MessagingResult Send(PingParameters pingParameters)
{
var encodedMessages = new List<string> {Encode(pingParameters).Content};
var messagingParameters = pingParameters.BuildMessagingParameter(encodedMessages);
return _messagingService.Send(messagingParameters);
}

/// <summary>
/// Please see base class declaration for documentation.
/// </summary>
/// <param name="pingParameters">-</param>
/// <returns>-</returns>
public Task<MessagingResult> SendAsync(PingParameters pingParameters)
{
var encodedMessages = new List<string> {Encode(pingParameters).Content};
var messagingParameters = pingParameters.BuildMessagingParameter(encodedMessages);
return _messagingService.SendAsync(messagingParameters);
}

/// <summary>
/// Please see <seealso cref="IEncodeMessageService{T}.Encode" /> for documentation.
/// </summary>
/// <param name="pingParameters">-</param>
/// <returns>-</returns>
public EncodedMessage Encode(PingParameters pingParameters)
{
var messageHeaderParameters = new MessageHeaderParameters
{
ApplicationMessageId = pingParameters.ApplicationMessageId,
TeamSetContextId = pingParameters.TeamsetContextId ?? "",
TechnicalMessageType = TechnicalMessageTypes.DkePing,
Mode = RequestEnvelope.Types.Mode.Direct
};

var messagePayloadParameters = new MessagePayloadParameters
{
TypeUrl = "",
Value = ByteString.Empty
};

var encodedMessage = new EncodedMessage
{
Id = Guid.NewGuid().ToString(),
Content = EncodeMessageService.Encode(messageHeaderParameters, messagePayloadParameters)
};

return encodedMessage;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Agrirouter.Api.Dto.Messaging;
using Agrirouter.Api.Dto.Onboard;
using Agrirouter.Api.Service.Parameters;
using Agrirouter.Impl.Service.Common;
using Agrirouter.Impl.Service.Messaging;
using Agrirouter.Test.Data;
using Agrirouter.Test.Helper;
using MQTTnet;
using MQTTnet.Client;
using Newtonsoft.Json;
using Xunit;

namespace Agrirouter.Test.Service.Messaging.Mqtt
{
[Collection("Integrationtest")]
public class PingServiceTest : AbstractIntegrationTestForCommunicationUnits
{
[Fact]
public async void
GivenExistingEndpointWhenSendingPingThenShouldBeSuccessful()
{
var mqttClient = new MqttFactory().CreateMqttClient();

await MqttConnectionHelper.ConnectMqttClient(mqttClient, OnboardResponse);
await MqttConnectionHelper.SubscribeToTopics(mqttClient, OnboardResponse);

var pingService = new PingService(new MqttMessagingService(mqttClient));
var pingParameters = new PingParameters()
{
OnboardResponse = OnboardResponse
};

pingService.Send(pingParameters);

var messageReceived = false;
var counter = 0;

mqttClient.UseApplicationMessageReceivedHandler(e =>
{
messageReceived = true;

var msg = JsonConvert.DeserializeObject<MessageResponse>(
Encoding.UTF8.GetString(e.ApplicationMessage.Payload));
var decodedMessage = DecodeMessageService.Decode(msg.Command.Message);

Assert.Equal(200, decodedMessage.ResponseEnvelope.ResponseCode);
});

while (!messageReceived && counter < 5)
{
await Task.Delay(TimeSpan.FromSeconds(5));
counter++;
}

Assert.True(messageReceived);
}

private static OnboardResponse OnboardResponse =>
OnboardResponseIntegrationService.Read(Identifier.Mqtt.CommunicationUnit.SingleEndpointWithP12Certificate);


[Fact(Skip =
"Concept only: A deleted endpoint can not be tested automatically and requires some manual actions.")]
public async void
GivenRecentlyDeletedEndpointWhenSendingPingThenShouldReturn400()
{
// This test case can not run. We have no Router Device based tests currently, and this command only
// makes sense with a Router Device.
// It is only intended to show the concept of the test case.

var mqttClient = new MqttFactory().CreateMqttClient();

await MqttConnectionHelper.ConnectMqttClient(mqttClient, OnboardResponse);
await MqttConnectionHelper.SubscribeToTopics(mqttClient, OnboardResponse);

// Endpoint would need to be deleted here
// if it was deleted earlier, the connection wouldn't be possible

var pingService = new PingService(new MqttMessagingService(mqttClient));
var pingParameters = new PingParameters()
{
OnboardResponse = OnboardResponse
};

pingService.Send(pingParameters);

var messageReceived = false;
var counter = 0;

mqttClient.UseApplicationMessageReceivedHandler(e =>
{
messageReceived = true;

var msg = JsonConvert.DeserializeObject<MessageResponse>(
Encoding.UTF8.GetString(e.ApplicationMessage.Payload));
var decodedMessage = DecodeMessageService.Decode(msg.Command.Message);

// your own application should remove the endpoint from your endpoint list/registry now!
Assert.Equal(400, decodedMessage.ResponseEnvelope.ResponseCode);
});

while (!messageReceived && counter < 5)
{
await Task.Delay(TimeSpan.FromSeconds(5));
counter++;
}

Assert.True(messageReceived);
}
}
}
Loading