littleshop/LittleShop.Tests/Unit/PushNotificationControllerTests.cs
2025-09-01 06:01:05 +01:00

353 lines
11 KiB
C#

using Xunit;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Moq;
using System.Security.Claims;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using LittleShop.Controllers;
using LittleShop.Services;
using LittleShop.DTOs;
namespace LittleShop.Tests.Unit;
public class PushNotificationControllerTests
{
private readonly Mock<IPushNotificationService> _pushServiceMock;
private readonly PushNotificationController _controller;
private readonly Guid _testUserId = Guid.NewGuid();
public PushNotificationControllerTests()
{
_pushServiceMock = new Mock<IPushNotificationService>();
_controller = new PushNotificationController(_pushServiceMock.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.Role, "Admin")
};
var identity = new ClaimsIdentity(claims, "TestAuth");
var principal = new ClaimsPrincipal(identity);
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = principal,
Connection = { RemoteIpAddress = System.Net.IPAddress.Parse("192.168.1.1") }
}
};
// Setup User-Agent header
_controller.HttpContext.Request.Headers.Add("User-Agent", "TestBrowser/1.0");
}
[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);
dynamic value = okResult.Value;
Assert.Equal(expectedKey, value.publicKey);
}
[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);
dynamic value = okResult.Value;
Assert.Equal("Successfully subscribed to push notifications", value.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);
dynamic value = unauthorizedResult.Value;
Assert.Equal("Invalid user ID", value.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);
dynamic value = okResult.Value;
Assert.Equal("Successfully subscribed to push notifications", value.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);
dynamic value = badRequestResult.Value;
Assert.Equal("Invalid customer ID", value.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);
dynamic value = okResult.Value;
Assert.Equal("Successfully unsubscribed from push notifications", value.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);
dynamic value = notFoundResult.Value;
Assert.Equal("Subscription not found", value.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);
dynamic value = okResult.Value;
Assert.Equal("Test notification sent successfully", value.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);
dynamic value = statusResult.Value;
Assert.Contains("Failed to send test notification", (string)value.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);
dynamic value = okResult.Value;
Assert.Equal("Broadcast notification sent successfully", value.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 subscriptionList = okResult.Value as IEnumerable<dynamic>;
Assert.NotNull(subscriptionList);
Assert.Single(subscriptionList);
}
[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);
dynamic value = okResult.Value;
Assert.Equal("Cleaned up 5 expired subscriptions", value.message);
}
}