Compare commits
2 commits
fae88aa262
...
7d7cf8148a
Author | SHA1 | Date | |
---|---|---|---|
7d7cf8148a | |||
306f3c25bc |
9 changed files with 284 additions and 45 deletions
10
pom.xml
10
pom.xml
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -49,6 +49,12 @@
|
|||
<version>4.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>4.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- to test my json implementation -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.Optional;
|
|||
import java.util.UUID;
|
||||
|
||||
public final class FileSystemDB implements PersistPlayer, FindPlayer {
|
||||
|
||||
private final File saveDirectory;
|
||||
private final SerializationFactory serializationFactory;
|
||||
|
||||
|
@ -22,29 +23,32 @@ public final class FileSystemDB implements PersistPlayer, FindPlayer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flush(final Player player) throws PersistException {
|
||||
public void flush(final Player player) throws WritePlayerException {
|
||||
final var playerFile = new File(saveDirectory, player.uuid().toString());
|
||||
final String serializedPlayer = serializationFactory.createSerializer(player).serialize();
|
||||
try (final var writer = new FileWriter(playerFile)) {
|
||||
final String jsonPlayer = serializationFactory.createSerializer(player).serialize();
|
||||
writer.write(jsonPlayer);
|
||||
writer.write(serializedPlayer);
|
||||
// ensure everything is written
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new PersistException("Could not persist player data with id: " + player.uuid(), e);
|
||||
throw new WritePlayerException("Could not persist player data from player: " + player.uuid(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Player> findById(final UUID uuid) throws FindPlayerException {
|
||||
public Optional<Player> findById(final UUID uuid) throws ReadPlayerException {
|
||||
final File[] files = getFiles();
|
||||
for (final var file : files) {
|
||||
if (file.getName().equals(uuid.toString())) {
|
||||
if (!file.getName().equals(uuid.toString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
final String fileContent = Files.readString(file.toPath());
|
||||
final Player player = serializationFactory.createDeserializer(fileContent);
|
||||
return Optional.of(player);
|
||||
} catch (IOException e) {
|
||||
throw new FindPlayerException("Player not found with the uuid: " + uuid, e);
|
||||
}
|
||||
throw new ReadPlayerException("Player not found with the uuid: " + uuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +56,7 @@ public final class FileSystemDB implements PersistPlayer, FindPlayer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<Player> findByName(final String name) throws FindPlayerException {
|
||||
public Optional<Player> findByName(final String name) throws ReadPlayerException {
|
||||
final File[] files = getFiles();
|
||||
for (final var file : files) {
|
||||
try {
|
||||
|
@ -62,7 +66,7 @@ public final class FileSystemDB implements PersistPlayer, FindPlayer {
|
|||
return Optional.of(player);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new FindPlayerException("Player not found with the name: " + name, e);
|
||||
throw new ReadPlayerException("Player not found with the name: " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +74,7 @@ public final class FileSystemDB implements PersistPlayer, FindPlayer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Player> findAll() throws FindPlayerException {
|
||||
public List<Player> findAll() throws ReadPlayerException {
|
||||
final File[] files = getFiles();
|
||||
final var playerList = new ArrayList<Player>();
|
||||
for (final var file : files) {
|
||||
|
@ -79,7 +83,7 @@ public final class FileSystemDB implements PersistPlayer, FindPlayer {
|
|||
final Player player = serializationFactory.createDeserializer(fileContent);
|
||||
playerList.add(player);
|
||||
} catch (IOException e) {
|
||||
throw new FindPlayerException("Player not found with the path: " + file.getAbsolutePath(), e);
|
||||
throw new ReadPlayerException("Player not found with the path: " + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import java.util.Optional;
|
|||
import java.util.UUID;
|
||||
|
||||
public interface FindPlayer {
|
||||
Optional<Player> findById(UUID uuid) throws FindPlayerException;
|
||||
Optional<Player> findById(UUID uuid) throws ReadPlayerException;
|
||||
|
||||
Optional<Player> findByName(String name) throws FindPlayerException;
|
||||
Optional<Player> findByName(String name) throws ReadPlayerException;
|
||||
|
||||
List<Player> findAll() throws FindPlayerException;
|
||||
List<Player> findAll() throws ReadPlayerException;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
public final class FindPlayerException extends Exception {
|
||||
public FindPlayerException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public FindPlayerException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class PersistException extends Exception {
|
||||
|
||||
public PersistException(final String message, final IOException cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,5 +3,5 @@ package de.hhhammer.playtime.ng.persistence;
|
|||
import de.hhhammer.playtime.ng.player.Player;
|
||||
|
||||
public interface PersistPlayer {
|
||||
void flush(Player player) throws PersistException;
|
||||
void flush(Player player) throws WritePlayerException;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
public final class ReadPlayerException extends Exception {
|
||||
public ReadPlayerException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public ReadPlayerException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class WritePlayerException extends Exception {
|
||||
|
||||
public WritePlayerException(final String message, final IOException cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import de.hhhammer.playtime.ng.serialization.SerializationFactory;
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.Serializer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FileSystemDBTest {
|
||||
|
||||
@Mock
|
||||
private SerializationFactory mockSerializationFactory;
|
||||
@Mock
|
||||
private Player mockPlayer;
|
||||
@Mock
|
||||
private Serializer mockSerializer;
|
||||
private File testDirectory;
|
||||
private FileSystemDB fileSystemDB;
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws IOException {
|
||||
final Path path = Files.createTempDirectory("playtime").toAbsolutePath();
|
||||
this.testDirectory = path.toFile();
|
||||
this.fileSystemDB = new FileSystemDB(testDirectory, mockSerializationFactory);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
testDirectory.delete();
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FlushTest {
|
||||
|
||||
@Test
|
||||
void shouldWriteFile() throws WritePlayerException {
|
||||
when(mockSerializationFactory.createSerializer(any())).thenReturn(mockSerializer);
|
||||
when(mockPlayer.uuid()).thenReturn(UUID.randomUUID());
|
||||
when(mockSerializer.serialize()).thenReturn("");
|
||||
|
||||
assertEquals(0, testDirectory.listFiles().length);
|
||||
|
||||
fileSystemDB.flush(mockPlayer);
|
||||
|
||||
assertEquals(1, testDirectory.listFiles().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNameFileWithPlayerUUID() throws WritePlayerException {
|
||||
final var uuid = UUID.randomUUID();
|
||||
when(mockSerializationFactory.createSerializer(any())).thenReturn(mockSerializer);
|
||||
when(mockPlayer.uuid()).thenReturn(uuid);
|
||||
when(mockSerializer.serialize()).thenReturn("");
|
||||
|
||||
fileSystemDB.flush(mockPlayer);
|
||||
|
||||
final File[] foundFiles = testDirectory.listFiles();
|
||||
assertEquals(1, foundFiles.length);
|
||||
assertEquals(uuid.toString(), foundFiles[0].getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWriteContentFromSerializer() throws WritePlayerException, IOException {
|
||||
when(mockSerializationFactory.createSerializer(any())).thenReturn(mockSerializer);
|
||||
when(mockPlayer.uuid()).thenReturn(UUID.randomUUID());
|
||||
final String content = "test content from serializer";
|
||||
when(mockSerializer.serialize()).thenReturn(content);
|
||||
|
||||
fileSystemDB.flush(mockPlayer);
|
||||
|
||||
final File[] foundFiles = testDirectory.listFiles();
|
||||
assertEquals(1, foundFiles.length);
|
||||
final String foundContent = Files.readString(foundFiles[0].toPath());
|
||||
assertEquals(content, foundContent);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FindById {
|
||||
|
||||
@Test
|
||||
void shouldThrowIfDirectoryIsAFile() {
|
||||
final var notADir = new File(testDirectory, "not_a_dir");
|
||||
final var fileSystemDB = new FileSystemDB(notADir, mockSerializationFactory);
|
||||
final Exception exception = assertThrows(RuntimeException.class, () -> fileSystemDB.findById(UUID.randomUUID()));
|
||||
assertEquals("Could not find files in: " + notADir.getAbsolutePath(), exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfNoFileIsPresent() throws IOException, ReadPlayerException {
|
||||
assertEquals(0, testDirectory.listFiles().length);
|
||||
|
||||
final Optional<Player> foundPlayer = fileSystemDB.findById(UUID.randomUUID());
|
||||
|
||||
assertTrue(foundPlayer.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfUuidNotFound() throws IOException, ReadPlayerException {
|
||||
new File(testDirectory, "not_a_uuid").createNewFile();
|
||||
|
||||
final Optional<Player> foundPlayer = fileSystemDB.findById(UUID.randomUUID());
|
||||
|
||||
assertTrue(foundPlayer.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeserializeFileContent() throws IOException, ReadPlayerException {
|
||||
final var playerUUID = UUID.randomUUID();
|
||||
final var fakePlayerFile = new File(testDirectory, playerUUID.toString());
|
||||
final String fileContent = "test content";
|
||||
Files.write(fakePlayerFile.toPath(), fileContent.getBytes());
|
||||
|
||||
when(mockSerializationFactory.createDeserializer(any())).thenReturn(mockPlayer);
|
||||
|
||||
fileSystemDB.findById(playerUUID);
|
||||
|
||||
verify(mockSerializationFactory).createDeserializer(fileContent);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FindByName {
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfNoFilesExist() throws ReadPlayerException {
|
||||
final Optional<Player> result = fileSystemDB.findByName("username");
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindThroughDeserializePlayerWithOnlyOneFile() throws IOException, ReadPlayerException {
|
||||
final var username = "username";
|
||||
when(mockPlayer.name()).thenReturn(username);
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "".getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final Optional<Player> result = fileSystemDB.findByName(username);
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFindThroughDeserializePlayerWithOnlyOneFile() throws IOException, ReadPlayerException {
|
||||
final var username = "username";
|
||||
when(mockPlayer.name()).thenReturn(username);
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "".getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final Optional<Player> result = fileSystemDB.findByName("not_a_username");
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindThroughDeserializePlayerOnMultipleFiles() throws IOException, ReadPlayerException {
|
||||
final var wantedUsername = "username";
|
||||
final var notWantedUsername = "not_wanted_username";
|
||||
final var rightPlayer = mock(Player.class);
|
||||
final var wrongPlayer = mock(Player.class);
|
||||
when(rightPlayer.name()).thenReturn(wantedUsername);
|
||||
when(wrongPlayer.name()).thenReturn(notWantedUsername);
|
||||
final var rightPlayerFileContent = "right";
|
||||
final var wrongPlayerFileContent = "wrong";
|
||||
final var rightPlayerFile = new File(testDirectory, "right_player_file");
|
||||
final var wrongPlayerFile = new File(testDirectory, "wrong_player_file");
|
||||
Files.write(rightPlayerFile.toPath(), rightPlayerFileContent.getBytes());
|
||||
Files.write(wrongPlayerFile.toPath(), wrongPlayerFileContent.getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(rightPlayerFileContent)).thenReturn(rightPlayer);
|
||||
when(mockSerializationFactory.createDeserializer(wrongPlayerFileContent)).thenReturn(wrongPlayer);
|
||||
|
||||
final Optional<Player> result = fileSystemDB.findByName(wantedUsername);
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FindAllTest {
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfNoFilesExist() throws ReadPlayerException {
|
||||
final List<Player> result = fileSystemDB.findAll();
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindOneFile() throws IOException, ReadPlayerException {
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "test content".getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final List<Player> result = fileSystemDB.findAll();
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindTwoFile() throws IOException, ReadPlayerException {
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "test content".getBytes());
|
||||
final var fakePlayerFile2 = new File(testDirectory, "fake_player_file_2");
|
||||
Files.write(fakePlayerFile2.toPath(), "test content".getBytes());
|
||||
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final List<Player> result = fileSystemDB.findAll();
|
||||
assertEquals(2, result.size());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue