- Changed JSON naming policy from CamelCase to SnakeCaseLower for SilverPay API compatibility - Fixed field name from 'fiat_amount' to 'amount' in request body - Used unique payment ID instead of order ID to avoid duplicate external_id conflicts - Modified SilverPayApiResponse to handle string amounts from API - Added [JsonIgnore] attributes to computed properties to prevent JSON serialization conflicts - Fixed test compilation errors (mock service and enum casting issues) - Updated SilverPay endpoint to http://10.0.0.52:8001/ 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
383 lines
13 KiB
C#
383 lines
13 KiB
C#
using Xunit;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Primitives;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using Moq;
|
|
using System.Security.Claims;
|
|
using System.Threading.Tasks;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using LittleShop.Controllers;
|
|
using LittleShop.Services;
|
|
using LittleShop.DTOs;
|
|
|
|
namespace LittleShop.Tests.Unit;
|
|
|
|
public class PushNotificationControllerTests
|
|
{
|
|
private readonly Mock<IPushNotificationService> _pushServiceMock;
|
|
private readonly Mock<ITeleBotMessagingService> _teleBotServiceMock;
|
|
private readonly PushNotificationController _controller;
|
|
private readonly Guid _testUserId = Guid.NewGuid();
|
|
|
|
public PushNotificationControllerTests()
|
|
{
|
|
_pushServiceMock = new Mock<IPushNotificationService>();
|
|
_teleBotServiceMock = new Mock<ITeleBotMessagingService>();
|
|
_controller = new PushNotificationController(_pushServiceMock.Object, _teleBotServiceMock.Object);
|
|
|
|
// Setup controller context for authenticated user
|
|
SetupControllerContext();
|
|
}
|
|
|
|
private void SetupControllerContext()
|
|
{
|
|
var claims = new List<Claim>
|
|
{
|
|
new Claim(ClaimTypes.NameIdentifier, _testUserId.ToString()),
|
|
new Claim(ClaimTypes.Name, "testuser"),
|
|
new Claim(ClaimTypes.Role, "Admin")
|
|
};
|
|
var identity = new ClaimsIdentity(claims, "TestAuth");
|
|
var principal = new ClaimsPrincipal(identity);
|
|
|
|
// Setup service provider with logger
|
|
var services = new ServiceCollection();
|
|
services.AddLogging();
|
|
var serviceProvider = services.BuildServiceProvider();
|
|
|
|
var httpContext = new DefaultHttpContext
|
|
{
|
|
User = principal,
|
|
Connection = { RemoteIpAddress = System.Net.IPAddress.Parse("192.168.1.1") },
|
|
RequestServices = serviceProvider
|
|
};
|
|
|
|
_controller.ControllerContext = new ControllerContext
|
|
{
|
|
HttpContext = httpContext
|
|
};
|
|
|
|
// Setup User-Agent header
|
|
_controller.HttpContext.Request.Headers.Add("User-Agent", "TestBrowser/1.0");
|
|
}
|
|
|
|
private string GetPropertyFromResult(object resultValue, string propertyName)
|
|
{
|
|
var jsonString = JsonSerializer.Serialize(resultValue);
|
|
var response = JsonSerializer.Deserialize<JsonElement>(jsonString);
|
|
|
|
// Handle case where the result is a simple string value
|
|
if (response.ValueKind == JsonValueKind.String)
|
|
{
|
|
return response.GetString()!;
|
|
}
|
|
|
|
return response.GetProperty(propertyName).GetString()!;
|
|
}
|
|
|
|
[Fact]
|
|
public void GetVapidPublicKey_ReturnsPublicKey()
|
|
{
|
|
// Arrange
|
|
var expectedKey = "test-public-key";
|
|
_pushServiceMock.Setup(s => s.GetVapidPublicKey()).Returns(expectedKey);
|
|
|
|
// Act
|
|
var result = _controller.GetVapidPublicKey();
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var jsonString = JsonSerializer.Serialize(okResult.Value);
|
|
var response = JsonSerializer.Deserialize<JsonElement>(jsonString);
|
|
Assert.Equal(expectedKey, response.GetProperty("publicKey").GetString());
|
|
}
|
|
|
|
[Fact]
|
|
public void GetVapidPublicKey_ReturnsInternalServerError_OnException()
|
|
{
|
|
// Arrange
|
|
_pushServiceMock.Setup(s => s.GetVapidPublicKey()).Throws(new Exception("Test exception"));
|
|
|
|
// Act
|
|
var result = _controller.GetVapidPublicKey();
|
|
|
|
// Assert
|
|
var statusResult = Assert.IsType<ObjectResult>(result);
|
|
Assert.Equal(500, statusResult.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Subscribe_ReturnsOk_WhenSubscriptionSuccessful()
|
|
{
|
|
// Arrange
|
|
var subscriptionDto = new PushSubscriptionDto
|
|
{
|
|
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
|
P256DH = "test-p256dh",
|
|
Auth = "test-auth"
|
|
};
|
|
|
|
_pushServiceMock
|
|
.Setup(s => s.SubscribeUserAsync(_testUserId, subscriptionDto, "TestBrowser/1.0", "192.168.1.1"))
|
|
.ReturnsAsync(true);
|
|
|
|
// Act
|
|
var result = await _controller.Subscribe(subscriptionDto);
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var message = GetPropertyFromResult(okResult.Value!, "message");
|
|
Assert.Equal("Successfully subscribed to push notifications", message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Subscribe_ReturnsInternalServerError_WhenSubscriptionFails()
|
|
{
|
|
// Arrange
|
|
var subscriptionDto = new PushSubscriptionDto
|
|
{
|
|
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
|
P256DH = "test-p256dh",
|
|
Auth = "test-auth"
|
|
};
|
|
|
|
_pushServiceMock
|
|
.Setup(s => s.SubscribeUserAsync(It.IsAny<Guid>(), It.IsAny<PushSubscriptionDto>(), It.IsAny<string>(), It.IsAny<string>()))
|
|
.ReturnsAsync(false);
|
|
|
|
// Act
|
|
var result = await _controller.Subscribe(subscriptionDto);
|
|
|
|
// Assert
|
|
var statusResult = Assert.IsType<ObjectResult>(result);
|
|
Assert.Equal(500, statusResult.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Subscribe_ReturnsUnauthorized_WhenUserIdInvalid()
|
|
{
|
|
// Arrange
|
|
// Setup controller with invalid user ID
|
|
var claims = new List<Claim>
|
|
{
|
|
new Claim(ClaimTypes.NameIdentifier, "invalid-guid"),
|
|
new Claim(ClaimTypes.Role, "Admin")
|
|
};
|
|
var identity = new ClaimsIdentity(claims, "TestAuth");
|
|
var principal = new ClaimsPrincipal(identity);
|
|
|
|
_controller.ControllerContext.HttpContext.User = principal;
|
|
|
|
var subscriptionDto = new PushSubscriptionDto
|
|
{
|
|
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
|
P256DH = "test-p256dh",
|
|
Auth = "test-auth"
|
|
};
|
|
|
|
// Act
|
|
var result = await _controller.Subscribe(subscriptionDto);
|
|
|
|
// Assert
|
|
var unauthorizedResult = Assert.IsType<UnauthorizedObjectResult>(result);
|
|
var error = GetPropertyFromResult(unauthorizedResult.Value!, "error");
|
|
Assert.Equal("Invalid user ID", error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SubscribeCustomer_ReturnsOk_WhenSuccessful()
|
|
{
|
|
// Arrange
|
|
var customerId = Guid.NewGuid();
|
|
var subscriptionDto = new PushSubscriptionDto
|
|
{
|
|
Endpoint = "https://fcm.googleapis.com/fcm/send/customer",
|
|
P256DH = "customer-p256dh",
|
|
Auth = "customer-auth"
|
|
};
|
|
|
|
_pushServiceMock
|
|
.Setup(s => s.SubscribeCustomerAsync(customerId, subscriptionDto, It.IsAny<string>(), It.IsAny<string>()))
|
|
.ReturnsAsync(true);
|
|
|
|
// Act
|
|
var result = await _controller.SubscribeCustomer(subscriptionDto, customerId);
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var message = GetPropertyFromResult(okResult.Value!, "message");
|
|
Assert.Equal("Successfully subscribed to push notifications", message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SubscribeCustomer_ReturnsBadRequest_WhenCustomerIdEmpty()
|
|
{
|
|
// Arrange
|
|
var subscriptionDto = new PushSubscriptionDto
|
|
{
|
|
Endpoint = "https://fcm.googleapis.com/fcm/send/customer",
|
|
P256DH = "customer-p256dh",
|
|
Auth = "customer-auth"
|
|
};
|
|
|
|
// Act
|
|
var result = await _controller.SubscribeCustomer(subscriptionDto, Guid.Empty);
|
|
|
|
// Assert
|
|
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
|
|
var error = GetPropertyFromResult(badRequestResult.Value!, "error");
|
|
Assert.Equal("Invalid customer ID", error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Unsubscribe_ReturnsOk_WhenSuccessful()
|
|
{
|
|
// Arrange
|
|
var unsubscribeDto = new UnsubscribeDto { Endpoint = "https://fcm.googleapis.com/fcm/send/test" };
|
|
_pushServiceMock.Setup(s => s.UnsubscribeAsync(unsubscribeDto.Endpoint)).ReturnsAsync(true);
|
|
|
|
// Act
|
|
var result = await _controller.Unsubscribe(unsubscribeDto);
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var message = GetPropertyFromResult(okResult.Value!, "message");
|
|
Assert.Equal("Successfully unsubscribed from push notifications", message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Unsubscribe_ReturnsNotFound_WhenSubscriptionNotFound()
|
|
{
|
|
// Arrange
|
|
var unsubscribeDto = new UnsubscribeDto { Endpoint = "https://fcm.googleapis.com/fcm/send/nonexistent" };
|
|
_pushServiceMock.Setup(s => s.UnsubscribeAsync(unsubscribeDto.Endpoint)).ReturnsAsync(false);
|
|
|
|
// Act
|
|
var result = await _controller.Unsubscribe(unsubscribeDto);
|
|
|
|
// Assert
|
|
var notFoundResult = Assert.IsType<NotFoundObjectResult>(result);
|
|
var error = GetPropertyFromResult(notFoundResult.Value!, "error");
|
|
Assert.Equal("Subscription not found", error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SendTestNotification_ReturnsOk_WhenSuccessful()
|
|
{
|
|
// Arrange
|
|
var testDto = new TestPushNotificationDto
|
|
{
|
|
Title = "Test Title",
|
|
Body = "Test Body"
|
|
};
|
|
|
|
_pushServiceMock
|
|
.Setup(s => s.SendTestNotificationAsync(_testUserId.ToString(), testDto.Title, testDto.Body))
|
|
.ReturnsAsync(true);
|
|
|
|
// Act
|
|
var result = await _controller.SendTestNotification(testDto);
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var message = GetPropertyFromResult(okResult.Value!, "message");
|
|
Assert.Equal("Test notification sent successfully", message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SendTestNotification_ReturnsInternalServerError_WhenFails()
|
|
{
|
|
// Arrange
|
|
var testDto = new TestPushNotificationDto
|
|
{
|
|
Title = "Test Title",
|
|
Body = "Test Body"
|
|
};
|
|
|
|
_pushServiceMock
|
|
.Setup(s => s.SendTestNotificationAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
|
|
.ReturnsAsync(false);
|
|
|
|
// Act
|
|
var result = await _controller.SendTestNotification(testDto);
|
|
|
|
// Assert
|
|
var statusResult = Assert.IsType<ObjectResult>(result);
|
|
Assert.Equal(500, statusResult.StatusCode);
|
|
var error = GetPropertyFromResult(statusResult.Value!, "error");
|
|
Assert.Contains("Failed to send test notification", error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SendBroadcastNotification_ReturnsOk_WhenSuccessful()
|
|
{
|
|
// Arrange
|
|
var notificationDto = new PushNotificationDto
|
|
{
|
|
Title = "Broadcast Title",
|
|
Body = "Broadcast Body"
|
|
};
|
|
|
|
_pushServiceMock
|
|
.Setup(s => s.SendNotificationToAllUsersAsync(notificationDto))
|
|
.ReturnsAsync(true);
|
|
|
|
// Act
|
|
var result = await _controller.SendBroadcastNotification(notificationDto);
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var message = GetPropertyFromResult(okResult.Value!, "message");
|
|
Assert.Equal("Broadcast notification sent successfully", message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetActiveSubscriptions_ReturnsOk_WithSubscriptions()
|
|
{
|
|
// Arrange
|
|
var subscriptions = new List<LittleShop.Models.PushSubscription>
|
|
{
|
|
new LittleShop.Models.PushSubscription
|
|
{
|
|
Id = 1,
|
|
UserId = _testUserId,
|
|
Endpoint = "https://fcm.googleapis.com/fcm/send/test-long-endpoint-that-should-be-truncated",
|
|
SubscribedAt = DateTime.UtcNow,
|
|
LastUsedAt = DateTime.UtcNow,
|
|
UserAgent = "TestBrowser/1.0",
|
|
User = new LittleShop.Models.User { Username = "testuser" }
|
|
}
|
|
};
|
|
|
|
_pushServiceMock.Setup(s => s.GetActiveSubscriptionsAsync()).ReturnsAsync(subscriptions);
|
|
|
|
// Act
|
|
var result = await _controller.GetActiveSubscriptions();
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var jsonString = JsonSerializer.Serialize(okResult.Value);
|
|
var subscriptionArray = JsonSerializer.Deserialize<JsonElement[]>(jsonString);
|
|
Assert.NotNull(subscriptionArray);
|
|
Assert.Single(subscriptionArray);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CleanupExpiredSubscriptions_ReturnsOk_WithCleanupCount()
|
|
{
|
|
// Arrange
|
|
_pushServiceMock.Setup(s => s.CleanupExpiredSubscriptionsAsync()).ReturnsAsync(5);
|
|
|
|
// Act
|
|
var result = await _controller.CleanupExpiredSubscriptions();
|
|
|
|
// Assert
|
|
var okResult = Assert.IsType<OkObjectResult>(result);
|
|
var message = GetPropertyFromResult(okResult.Value!, "message");
|
|
Assert.Equal("Cleaned up 5 expired subscriptions", message);
|
|
}
|
|
} |