Skip to content

Commit

Permalink
Implement remaining methods for users TCP client
Browse files Browse the repository at this point in the history
  • Loading branch information
mmodzelewski committed Oct 11, 2024
1 parent 7eadb89 commit 5d8e483
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/main/java/rs/iggy/clients/blocking/UsersClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ default UserInfoDetails getUser(Long userId) {

List<UserInfo> getUsers();

void createUser(String username, String password, UserStatus status, Optional<Permissions> permissions);
UserInfoDetails createUser(String username, String password, UserStatus status, Optional<Permissions> permissions);

default void deleteUser(Long userId) {
deleteUser(UserId.of(userId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ public List<UserInfo> getUsers() {
}

@Override
public void createUser(String username, String password, UserStatus status, Optional<Permissions> permissions) {
public UserInfoDetails createUser(String username, String password, UserStatus status, Optional<Permissions> permissions) {
var request = httpClient.preparePostRequest(USERS, new CreateUser(username, password, status, permissions));
httpClient.execute(request);
return httpClient.execute(request, new TypeReference<>() {
});
}

@Override
Expand Down Expand Up @@ -71,7 +72,7 @@ public IdentityInfo login(String username, String password) {

@Override
public void logout() {
var request = httpClient.preparePostRequest(USERS + "/logout", Optional.empty());
var request = httpClient.prepareDeleteRequest(USERS + "/logout");
httpClient.execute(request);
httpClient.setToken(Optional.empty());
}
Expand Down
68 changes: 68 additions & 0 deletions src/main/java/rs/iggy/clients/blocking/tcp/BytesSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
import rs.iggy.message.MessageToSend;
import rs.iggy.message.Partitioning;
import rs.iggy.message.PollingStrategy;
import rs.iggy.user.GlobalPermissions;
import rs.iggy.user.Permissions;
import rs.iggy.user.StreamPermissions;
import rs.iggy.user.TopicPermissions;
import java.math.BigInteger;
import java.util.Map;

Expand Down Expand Up @@ -95,6 +99,70 @@ static ByteBuf toBytes(Map<String, HeaderValue> headers) {
return buffer;
}

static ByteBuf toBytes(Permissions permissions) {
var buffer = Unpooled.buffer();
buffer.writeBytes(toBytes(permissions.global()));
if (permissions.streams().isEmpty()) {
buffer.writeByte(0);
} else {
for (Map.Entry<Long, StreamPermissions> entry : permissions.streams().entrySet()) {
buffer.writeByte(1);
buffer.writeIntLE(entry.getKey().intValue());
buffer.writeBytes(toBytes(entry.getValue()));
}
buffer.writeByte(0);
}

return buffer;
}

static ByteBuf toBytes(GlobalPermissions permissions) {
var buffer = Unpooled.buffer();
buffer.writeBoolean(permissions.manageServers());
buffer.writeBoolean(permissions.readServers());
buffer.writeBoolean(permissions.manageUsers());
buffer.writeBoolean(permissions.readUsers());
buffer.writeBoolean(permissions.manageStreams());
buffer.writeBoolean(permissions.readStreams());
buffer.writeBoolean(permissions.manageTopics());
buffer.writeBoolean(permissions.readTopics());
buffer.writeBoolean(permissions.pollMessages());
buffer.writeBoolean(permissions.sendMessages());
return buffer;
}

static ByteBuf toBytes(StreamPermissions permissions) {
var buffer = Unpooled.buffer();
buffer.writeBoolean(permissions.manageStream());
buffer.writeBoolean(permissions.readStream());
buffer.writeBoolean(permissions.manageTopics());
buffer.writeBoolean(permissions.readTopics());
buffer.writeBoolean(permissions.pollMessages());
buffer.writeBoolean(permissions.sendMessages());

if (permissions.topics().isEmpty()) {
buffer.writeByte(0);
} else {
for (Map.Entry<Long, TopicPermissions> entry : permissions.topics().entrySet()) {
buffer.writeByte(1);
buffer.writeIntLE(entry.getKey().intValue());
buffer.writeBytes(toBytes(entry.getValue()));
}
buffer.writeByte(0);
}

return buffer;
}

static ByteBuf toBytes(TopicPermissions permissions) {
var buffer = Unpooled.buffer();
buffer.writeBoolean(permissions.manageTopic());
buffer.writeBoolean(permissions.readTopic());
buffer.writeBoolean(permissions.pollMessages());
buffer.writeBoolean(permissions.sendMessages());
return buffer;
}

static ByteBuf toBytesAsU64(BigInteger value) {
if (value.signum() == -1) {
throw new IllegalArgumentException("Negative value cannot be serialized to unsigned 64: " + value);
Expand Down
54 changes: 45 additions & 9 deletions src/main/java/rs/iggy/clients/blocking/tcp/UsersTcpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,64 @@ public List<UserInfo> getUsers() {
}

@Override
public void createUser(String username, String password, UserStatus status, Optional<Permissions> permissions) {
throw new UnsupportedOperationException();
public UserInfoDetails createUser(String username, String password, UserStatus status, Optional<Permissions> permissions) {
var payload = Unpooled.buffer();
payload.writeBytes(nameToBytes(username));
payload.writeBytes(nameToBytes(password));
payload.writeByte(status.asCode());
permissions.ifPresentOrElse(perms -> {
payload.writeByte(1);
var permissionBytes = toBytes(perms);
payload.writeIntLE(permissionBytes.readableBytes());
payload.writeBytes(permissionBytes);
}, () -> payload.writeByte(0));

var response = connection.send(CREATE_USER_CODE, payload);
return readUserInfoDetails(response);
}

@Override
public void deleteUser(UserId userId) {
throw new UnsupportedOperationException();
var payload = toBytes(userId);
connection.send(DELETE_USER_CODE, payload);
}

@Override
public void updateUser(UserId userId, Optional<String> username, Optional<UserStatus> status) {
throw new UnsupportedOperationException();
public void updateUser(UserId userId, Optional<String> usernameOptional, Optional<UserStatus> statusOptional) {
var payload = toBytes(userId);
usernameOptional.ifPresentOrElse((username) -> {
payload.writeByte(1);
payload.writeBytes(nameToBytes(username));
}, () -> payload.writeByte(0));
statusOptional.ifPresentOrElse((status) -> {
payload.writeByte(1);
payload.writeByte(status.asCode());
}, () -> payload.writeByte(0));

connection.send(UPDATE_USER_CODE, payload);
}

@Override
public void updatePermissions(UserId userId, Optional<Permissions> permissions) {
throw new UnsupportedOperationException();
public void updatePermissions(UserId userId, Optional<Permissions> permissionsOptional) {
var payload = toBytes(userId);

permissionsOptional.ifPresentOrElse(permissions -> {
payload.writeByte(1);
var permissionBytes = toBytes(permissions);
payload.writeIntLE(permissionBytes.readableBytes());
payload.writeBytes(permissionBytes);
}, () -> payload.writeByte(0));

connection.send(UPDATE_PERMISSIONS_CODE, payload);
}

@Override
public void changePassword(UserId userId, String currentPassword, String newPassword) {
throw new UnsupportedOperationException();
var payload = toBytes(userId);
payload.writeBytes(nameToBytes(currentPassword));
payload.writeBytes(nameToBytes(newPassword));

connection.send(CHANGE_PASSWORD_CODE, payload);
}

@Override
Expand All @@ -93,6 +129,6 @@ public IdentityInfo login(String username, String password) {

@Override
public void logout() {
throw new UnsupportedOperationException();
connection.send(LOGOUT_USER_CODE);
}
}
8 changes: 6 additions & 2 deletions src/main/java/rs/iggy/user/UserStatus.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package rs.iggy.user;

public enum UserStatus {
Active(1),
Inactive(2);
active(1),
inactive(2);

private final int code;

Expand All @@ -18,4 +18,8 @@ public static UserStatus fromCode(int code) {
}
throw new IllegalArgumentException("Invalid user status: " + code);
}

public int asCode() {
return code;
}
}
85 changes: 83 additions & 2 deletions src/test/java/rs/iggy/clients/blocking/UsersClientBaseTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package rs.iggy.clients.blocking;

import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import rs.iggy.user.UserInfoDetails;
import rs.iggy.user.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;

public abstract class UsersClientBaseTest extends IntegrationTest {
Expand All @@ -26,12 +30,89 @@ void shouldLogin() {

@Test
void shouldGetUser() {
// when
// given
login();

// when
UserInfoDetails user = usersClient.getUser(1L);

// then
assertThat(user).isNotNull();
}

@Test
void shouldCreateAndDeleteUser() {
// given
login();

// when
var createdUser = usersClient.createUser("test", "test", UserStatus.active, Optional.of(new Permissions(createGlobalPermissions(true), Collections.emptyMap())));

// then
assertThat(createdUser).isNotNull();
assertThat(createdUser.permissions().map(Permissions::global).map(GlobalPermissions::manageServers).orElse(false)).isTrue();

// when
List<UserInfo> users = usersClient.getUsers();

// then
assertThat(users).hasSize(2);
assertThat(users).map(UserInfo::username).containsExactlyInAnyOrder("iggy", "test");

// when
usersClient.deleteUser(createdUser.id());

// then
users = usersClient.getUsers();
assertThat(users).hasSize(1);
}

@Test
void shouldUpdateUserStatus() {
// given
login();
UserInfoDetails user = usersClient.createUser("test", "test", UserStatus.active, Optional.empty());

// when
usersClient.updateUser(user.id(), Optional.empty(), Optional.of(UserStatus.inactive));

// then
List<UserInfo> users = usersClient.getUsers();
assertThat(users).map(UserInfo::status).contains(UserStatus.inactive);
}

@Test
void shouldUpdateUserPermissions() {
// given
var permissions = new Permissions(createGlobalPermissions(true), Collections.emptyMap());
login();
UserInfoDetails user = usersClient.createUser("test", "test", UserStatus.active, Optional.of(permissions));

// when
usersClient.updatePermissions(user.id(), Optional.of(new Permissions(createGlobalPermissions(false), Collections.emptyMap())));

// then
var updatedUser = usersClient.getUser(user.id());
assertThat(updatedUser).isNotNull();
assertThat(updatedUser.permissions().map(Permissions::global).map(GlobalPermissions::manageServers).orElse(true)).isFalse();
}

@Test
void shouldChangePassword() {
// given
IdentityInfo identity = usersClient.login("iggy", "iggy");

// when
usersClient.changePassword(identity.userId(), "iggy", "new-pass");
usersClient.logout();
IdentityInfo newLogin = usersClient.login("iggy", "new-pass");

// then
assertThat(newLogin).isNotNull();
}

private static @NotNull GlobalPermissions createGlobalPermissions(boolean manageServers) {
return new GlobalPermissions(manageServers, false, false, false, false, false, false, false, false, false);
}

}

0 comments on commit 5d8e483

Please sign in to comment.