Skip to content

Commit

Permalink
feat: implement request creation for audio connector
Browse files Browse the repository at this point in the history
  • Loading branch information
Tr00d committed Jul 17, 2024
1 parent 550df07 commit 1ecb51e
Show file tree
Hide file tree
Showing 9 changed files with 540 additions and 2 deletions.
11 changes: 11 additions & 0 deletions Vonage.Test/Video/AudioConnector/Start/E2ETest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#region
using Xunit;
#endregion

namespace Vonage.Test.Video.AudioConnector.Start;

[
Trait("Category", "E2E")]
public class E2ETest
{
}
239 changes: 239 additions & 0 deletions Vonage.Test/Video/AudioConnector/Start/RequestBuilderTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#region
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Vonage.Test.Common.Extensions;
using Vonage.Video.AudioConnector.Start;
using Xunit;
#endregion

namespace Vonage.Test.Video.AudioConnector.Start;

[Trait("Category", "Request")]
public class RequestBuilderTest
{
private const string ValidSessionId = "session-id";
private const string ValidToken = "token";
private readonly Guid validApplicationId = Guid.NewGuid();
private readonly Uri validUri = new Uri("https://example.com");

[Fact]
public void Build_ShouldSetApplicationId() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.ApplicationId)
.Should()
.BeSuccess(this.validApplicationId);

[Fact]
public void Build_ShouldSetToken() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.Token)
.Should()
.BeSuccess(ValidToken);

[Fact]
public void Build_ShouldSetSessionId() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.SessionId)
.Should()
.BeSuccess(ValidSessionId);

[Fact]
public void Build_ShouldSetUri() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.WebSocket.Uri)
.Should()
.BeSuccess(this.validUri);

[Fact]
public void Build_ShouldHaveDefaultAudioRate() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.WebSocket.AudioRate)
.Should()
.BeSuccess(SupportedAudioRates.AUDIO_RATE_8000Hz);

[Fact]
public void Build_ShouldSetAudioRate() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.WithAudioRate(SupportedAudioRates.AUDIO_RATE_16000Hz)
.Create()
.Map(request => request.WebSocket.AudioRate)
.Should()
.BeSuccess(SupportedAudioRates.AUDIO_RATE_16000Hz);

[Fact]
public void Build_ShouldHaveEmptyStreams_GivenDefault() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.WebSocket.Streams)
.Should()
.BeSuccess(Enumerable.Empty<string>().ToArray());

[Fact]
public void Build_ShouldSetStreams() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.WithStream("stream-1")
.WithStream("stream-2")
.Create()
.Map(request => request.WebSocket.Streams)
.Should()
.BeSuccess(new[] {"stream-1", "stream-2"});

[Fact]
public void Build_ShouldSetStreamsWithoutDuplicates() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.WithStream("stream-1")
.WithStream("stream-2")
.WithStream("stream-1")
.WithStream("stream-2")
.Create()
.Map(request => request.WebSocket.Streams)
.Should()
.BeSuccess(new[] {"stream-1", "stream-2"});

[Fact]
public void Build_ShouldHaveEmptyHeaders_GivenDefault() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Map(request => request.WebSocket.Headers)
.Should()
.BeSuccess(headers => headers.Should().BeEmpty());

[Fact]
public void Build_ShouldSetHeaders() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.WithHeader(new KeyValuePair<string, string>("key1", "value1"))
.WithHeader(new KeyValuePair<string, string>("key2", "value2"))
.Create()
.Map(request => request.WebSocket.Headers)
.Should()
.BeSuccess(headers => headers.Should().BeEquivalentTo(new[]
{
new KeyValuePair<string, string>("key1", "value1"),
new KeyValuePair<string, string>("key2", "value2"),
}));

[Fact]
public void Build_ShouldSetHeadersWithoutDuplicates() =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.WithHeader(new KeyValuePair<string, string>("key1", "value1"))
.WithHeader(new KeyValuePair<string, string>("key2", "value2"))
.WithHeader(new KeyValuePair<string, string>("key1", "value3"))
.WithHeader(new KeyValuePair<string, string>("key2", "value4"))
.Create()
.Map(request => request.WebSocket.Headers)
.Should()
.BeSuccess(headers => headers.Should().BeEquivalentTo(new[]
{
new KeyValuePair<string, string>("key1", "value1"),
new KeyValuePair<string, string>("key2", "value2"),
}));

[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void Parse_ShouldReturnFailure_GivenSessionIdIsEmpty(string invalidId) =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(invalidId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Should()
.BeParsingFailure("SessionId cannot be null or whitespace.");

[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void Parse_ShouldReturnFailure_GivenTokenIsEmpty(string invalidToken) =>
StartRequest
.Build()
.WithApplicationId(this.validApplicationId)
.WithSessionId(invalidToken)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Should()
.BeParsingFailure("SessionId cannot be null or whitespace.");

[Fact]
public void Parse_ShouldReturnFailure_GivenApplicationIdIsEmpty() =>
StartRequest
.Build()
.WithApplicationId(Guid.Empty)
.WithSessionId(ValidSessionId)
.WithToken(ValidToken)
.WithUrl(this.validUri)
.Create()
.Should()
.BeParsingFailure("ApplicationId cannot be empty.");
}
25 changes: 25 additions & 0 deletions Vonage.Test/Video/AudioConnector/Start/RequestTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#region
using System;
using Vonage.Test.Common.Extensions;
using Vonage.Video.AudioConnector.Start;
using Xunit;
#endregion

namespace Vonage.Test.Video.AudioConnector.Start;

[Trait("Category", "Request")]
public class RequestTest
{
[Fact]
public void GetEndpointPath_ShouldReturnApiEndpoint() =>
StartRequest
.Build()
.WithApplicationId(new Guid("301cf3c3-0027-4578-b212-dac7e924e85b"))
.WithSessionId("irrelevant")
.WithToken("irrelevant")
.WithUrl(new Uri("https://irrelevant.com"))
.Create()
.Map(request => request.GetEndpointPath())
.Should()
.BeSuccess("/v2/project/301cf3c3-0027-4578-b212-dac7e924e85b/connect");
}
10 changes: 10 additions & 0 deletions Vonage.Test/Video/AudioConnector/Start/SerializationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#region
using Xunit;
#endregion

namespace Vonage.Test.Video.AudioConnector.Start;

[Trait("Category", "Serialization")]
public class SerializationTest
{
}
1 change: 1 addition & 0 deletions Vonage.Test/Vonage.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Video\AudioConnector\Start\Data\"/>
<None Update="Data\NccoTests\TestRecord-request.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
89 changes: 89 additions & 0 deletions Vonage/Video/AudioConnector/Start/StartRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#region
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json.Serialization;
using Vonage.Common.Client;
using Vonage.Serialization;
#endregion

namespace Vonage.Video.AudioConnector.Start;

/// <inheritdoc />
public readonly struct StartRequest : IVonageRequest
{
/// <summary>
/// </summary>
[JsonPropertyOrder(1)]
public string Token { get; internal init; }

/// <summary>
/// </summary>
[JsonIgnore]
public Guid ApplicationId { get; internal init; }

/// <summary>
/// </summary>
[JsonPropertyOrder(0)]
public string SessionId { get; internal init; }

/// <summary>
/// </summary>
[JsonPropertyOrder(2)]
public WebSocket WebSocket { get; internal init; }

/// <inheritdoc />
public HttpRequestMessage BuildRequestMessage() => VonageRequestBuilder
.Initialize(HttpMethod.Post, this.GetEndpointPath())
.WithContent(this.GetRequestContent())
.Build();

private StringContent GetRequestContent() =>
new StringContent(JsonSerializerBuilder.BuildWithCamelCase().SerializeObject(this), Encoding.UTF8,
"application/json");

/// <inheritdoc />
public string GetEndpointPath() => $"/v2/project/{this.ApplicationId}/connect";

/// <summary>
/// Initializes a builder.
/// </summary>
/// <returns>The builder.</returns>
public static IBuilderForApplicationId Build() => new StartRequestBuilder();
}

/// <summary>
/// Represents a websocket configuration.
/// </summary>
/// <param name="Uri">A publicly reachable WebSocket URI to be used for the destination of the audio stream</param>
/// <param name="Streams">
/// An array of stream IDs for the Vonage Video streams you want to include in the WebSocket audio.
/// If you omit this property, all streams in the session will be included.
/// </param>
/// <param name="Headers">
/// An object of key-value pairs of headers to be sent to your WebSocket server with each message,
/// with a maximum length of 512 bytes.
/// </param>
/// <param name="AudioRate">A number representing the audio sampling rate in Hz.</param>
public record WebSocket(
Uri Uri,
string[] Streams,
Dictionary<string, string> Headers,
SupportedAudioRates AudioRate);

/// <summary>
/// A number representing the audio sampling rate in Hz.
/// </summary>
public enum SupportedAudioRates
{
/// <summary>
/// 8000Hz
/// </summary>
AUDIO_RATE_8000Hz,

/// <summary>
/// 16000Hz
/// </summary>
AUDIO_RATE_16000Hz,
}
Loading

0 comments on commit 1ecb51e

Please sign in to comment.