blob: 3f0a08e30cc80bc7b68e5a7a39e64b5c153431e3 [file]
// // Licensed to the Apache Software Foundation (ASF) under one
// // or more contributor license agreements. See the NOTICE file
// // distributed with this work for additional information
// // regarding copyright ownership. The ASF licenses this file
// // to you under the Apache License, Version 2.0 (the
// // "License"); you may not use this file except in compliance
// // with the License. You may obtain a copy of the License at
// //
// // http://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing,
// // software distributed under the License is distributed on an
// // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// // KIND, either express or implied. See the License for the
// // specific language governing permissions and limitations
// // under the License.
using Apache.Iggy.Contracts;
using Apache.Iggy.Contracts.Auth;
using Apache.Iggy.Contracts.Http.Auth;
using Apache.Iggy.Enums;
using Apache.Iggy.Exceptions;
using Apache.Iggy.Tests.Integrations.Fixtures;
using Shouldly;
namespace Apache.Iggy.Tests.Integrations;
public class UsersTests
{
[ClassDataSource<IggyServerFixture>(Shared = SharedType.PerAssembly)]
public required IggyServerFixture Fixture { get; init; }
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task CreateUser_Should_CreateUser_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"user-{Guid.NewGuid():N}"[..20];
var result = await client.CreateUser(username, "test_password_1", UserStatus.Active);
result.ShouldNotBeNull();
result.Username.ShouldBe(username);
result.Status.ShouldBe(UserStatus.Active);
result.Id.ShouldBeGreaterThan(0u);
result.CreatedAt.ShouldBeGreaterThan(0u);
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task CreateUser_Duplicate_Should_Throw_InvalidResponse(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"dup-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "test1", UserStatus.Active);
await Should.ThrowAsync<IggyInvalidStatusCodeException>(
client.CreateUser(username, "test1", UserStatus.Active));
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task GetUser_WithoutPermissions_Should_ReturnValidResponse(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"get-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "test1", UserStatus.Active);
var response = await client.GetUser(Identifier.String(username));
response.ShouldNotBeNull();
response.Id.ShouldBeGreaterThanOrEqualTo(0u);
response.Username.ShouldBe(username);
response.Status.ShouldBe(UserStatus.Active);
response.CreatedAt.ShouldBeGreaterThan(0u);
response.Permissions.ShouldBeNull();
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task GetUsers_Should_ReturnValidResponse(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"lst-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "test1", UserStatus.Active);
IReadOnlyList<UserResponse> response = await client.GetUsers();
response.ShouldNotBeNull();
response.ShouldNotBeEmpty();
response.ShouldContain(user => user.Username == username && user.Status == UserStatus.Active);
response.ShouldAllBe(user => user.CreatedAt > 0u);
response.ShouldAllBe(user => user.Permissions == null);
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task UpdateUser_Should_UpdateUser_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"upd-{Guid.NewGuid():N}"[..20];
var newUsername = $"new-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "test1", UserStatus.Active);
await Should.NotThrowAsync(client.UpdateUser(Identifier.String(username), newUsername, UserStatus.Active));
var user = await client.GetUser(Identifier.String(newUsername));
user.ShouldNotBeNull();
user.Id.ShouldBeGreaterThanOrEqualTo(0u);
user.Username.ShouldBe(newUsername);
user.Status.ShouldBe(UserStatus.Active);
user.CreatedAt.ShouldBeGreaterThan(0u);
user.Permissions.ShouldBeNull();
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task UpdatePermissions_Should_UpdatePermissions_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"perm-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "test1", UserStatus.Active);
var permissions = CreatePermissions();
await Should.NotThrowAsync(client.UpdatePermissions(Identifier.String(username), permissions));
var user = await client.GetUser(Identifier.String(username));
user.ShouldNotBeNull();
user.Permissions.ShouldNotBeNull();
user.Permissions!.Global.ShouldNotBeNull();
user.Permissions.Global.ManageServers.ShouldBeTrue();
user.Permissions.Global.ManageUsers.ShouldBeTrue();
user.Permissions.Global.ManageStreams.ShouldBeTrue();
user.Permissions.Global.ManageTopics.ShouldBeTrue();
user.Permissions.Global.PollMessages.ShouldBeTrue();
user.Permissions.Global.ReadServers.ShouldBeTrue();
user.Permissions.Global.ReadStreams.ShouldBeTrue();
user.Permissions.Global.ReadTopics.ShouldBeTrue();
user.Permissions.Global.ReadUsers.ShouldBeTrue();
user.Permissions.Global.SendMessages.ShouldBeTrue();
user.Permissions.Streams.ShouldNotBeNull();
user.Permissions.Streams.ShouldContainKey(1);
user.Permissions.Streams[1].ManageStream.ShouldBeTrue();
user.Permissions.Streams[1].ManageTopics.ShouldBeTrue();
user.Permissions.Streams[1].ReadStream.ShouldBeTrue();
user.Permissions.Streams[1].SendMessages.ShouldBeTrue();
user.Permissions.Streams[1].ReadTopics.ShouldBeTrue();
user.Permissions.Streams[1].PollMessages.ShouldBeTrue();
user.Permissions.Streams[1].Topics.ShouldNotBeNull();
user.Permissions.Streams[1].Topics!.ShouldContainKey(1);
user.Permissions.Streams[1].Topics![1].ManageTopic.ShouldBeTrue();
user.Permissions.Streams[1].Topics![1].PollMessages.ShouldBeTrue();
user.Permissions.Streams[1].Topics![1].ReadTopic.ShouldBeTrue();
user.Permissions.Streams[1].Topics![1].SendMessages.ShouldBeTrue();
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task ChangePassword_Should_ChangePassword_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"chpw-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "old_password", UserStatus.Active);
await Should.NotThrowAsync(client.ChangePassword(Identifier.String(username), "old_password", "new_password"));
// Verify password was actually changed by logging in with the new credentials
var loginClient = await Fixture.CreateClient(protocol);
var loginResponse = await loginClient.LoginUser(username, "new_password");
loginResponse.ShouldNotBeNull();
loginResponse.UserId.ShouldBeGreaterThan(0);
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task ChangePassword_WrongCurrentPassword_Should_Throw_InvalidResponse(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"chpwf-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "correct_password", UserStatus.Active);
await Should.ThrowAsync<IggyInvalidStatusCodeException>(
client.ChangePassword(Identifier.String(username), "wrong_password", "new_password"));
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task LoginUser_Should_LoginUser_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"login-{Guid.NewGuid():N}"[..20];
await client.CreateUser(username, "login_password", UserStatus.Active);
var loginClient = await Fixture.CreateClient(protocol);
var response = await loginClient.LoginUser(username, "login_password");
response.ShouldNotBeNull();
response.UserId.ShouldBeGreaterThan(0);
switch (protocol)
{
case Protocol.Tcp:
response.AccessToken.ShouldBeNull();
break;
case Protocol.Http:
response.AccessToken.ShouldNotBeNull();
break;
}
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task DeleteUser_Should_DeleteUser_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
var username = $"del-{Guid.NewGuid():N}"[..20];
var userToRemove = await client.CreateUser(username, "test123", UserStatus.Active);
userToRemove.ShouldNotBeNull();
await Should.NotThrowAsync(client.DeleteUser(Identifier.String(userToRemove.Username)));
}
[Test]
[MethodDataSource<IggyServerFixture>(nameof(IggyServerFixture.ProtocolData))]
public async Task LogoutUser_Should_LogoutUser_Successfully(Protocol protocol)
{
var client = await Fixture.CreateAuthenticatedClient(protocol);
await Should.NotThrowAsync(client.LogoutUser());
}
private static Permissions CreatePermissions()
{
return new Permissions
{
Global = new GlobalPermissions
{
ManageServers = true,
ManageUsers = true,
ManageStreams = true,
ManageTopics = true,
PollMessages = true,
ReadServers = true,
ReadStreams = true,
ReadTopics = true,
ReadUsers = true,
SendMessages = true
},
Streams = new Dictionary<int, StreamPermissions>
{
{
1, new StreamPermissions
{
ManageStream = true,
ManageTopics = true,
ReadStream = true,
SendMessages = true,
ReadTopics = true,
PollMessages = true,
Topics = new Dictionary<int, TopicPermissions>
{
{
1, new TopicPermissions
{
ManageTopic = true,
PollMessages = true,
ReadTopic = true,
SendMessages = true
}
}
}
}
}
}
};
}
}