meals-made-easy-api/src/integrationTest/java/app/mealsmadeeasy/api/image/S3ImageServiceTests.java
2025-12-27 18:48:10 -06:00

264 lines
9.8 KiB
Java

package app.mealsmadeeasy.api.image;
import app.mealsmadeeasy.api.IntegrationTestsExtension;
import app.mealsmadeeasy.api.image.spec.ImageCreateInfoSpec;
import app.mealsmadeeasy.api.image.spec.ImageUpdateInfoSpec;
import app.mealsmadeeasy.api.user.User;
import app.mealsmadeeasy.api.user.UserCreateException;
import app.mealsmadeeasy.api.user.UserService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MinIOContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import static app.mealsmadeeasy.api.image.ContainsImagesMatcher.containsImages;
import static app.mealsmadeeasy.api.user.ContainsUsersMatcher.containsUsers;
import static app.mealsmadeeasy.api.user.IsUserMatcher.isUser;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@Testcontainers
@SpringBootTest
@ExtendWith(IntegrationTestsExtension.class)
public class S3ImageServiceTests {
@Container
private static final MinIOContainer container = new MinIOContainer(
DockerImageName.parse("minio/minio:latest")
);
@DynamicPropertySource
public static void minioProperties(DynamicPropertyRegistry registry) {
registry.add("app.mealsmadeeasy.api.minio.endpoint", container::getS3URL);
registry.add("app.mealsmadeeasy.api.minio.accessKey", container::getUserName);
registry.add("app.mealsmadeeasy.api.minio.secretKey", container::getPassword);
}
private static InputStream getHal9000InputStream() {
return S3ImageServiceTests.class.getResourceAsStream("HAL9000.svg");
}
@Autowired
private UserService userService;
@Autowired
private ImageService imageService;
private static final String TEST_PASSWORD = "test";
private static final long HAL_LENGTH = 27881L;
private User seedUser() {
final String uuid = UUID.randomUUID().toString();
try {
return this.userService.createUser(uuid, uuid + "@test.com", TEST_PASSWORD);
} catch (UserCreateException e) {
throw new RuntimeException(e);
}
}
private static String makeUserFilename() {
return UUID.randomUUID() + ".svg";
}
private Image seedImage(User owner, ImageCreateInfoSpec spec) {
try (final InputStream hal9000 = getHal9000InputStream()) {
return this.imageService.create(
owner,
makeUserFilename(),
hal9000,
HAL_LENGTH,
spec
);
} catch (ImageException | IOException e) {
throw new RuntimeException(e);
}
}
private Image seedImage(User owner) {
return this.seedImage(owner, new ImageCreateInfoSpec());
}
private Image makePublic(Image image, User modifier) {
final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec();
spec.setPublic(true);
return this.imageService.update(image, modifier, spec);
}
@Test
public void smokeScreen() {}
@Test
public void simpleCreate() {
final User owner = this.seedUser();
final Image image = this.seedImage(owner);
assertThat(image.getOwner(), isUser(owner));
assertThat(image.getCreated(), is(notNullValue()));
assertThat(image.getModified(), is(nullValue()));
assertThat(image.getUserFilename(), is(notNullValue()));
assertThat(image.getMimeType(), is("image/svg+xml"));
assertThat(image.getAlt(), is(nullValue()));
assertThat(image.getCaption(), is(nullValue()));
assertThat(image.isPublic(), is(false));
assertThat(image.getViewers(), is(empty()));
}
@Test
public void properlyLoadsContent() throws IOException {
final User owner = this.seedUser();
final Image image = this.seedImage(owner);
final InputStream content = assertDoesNotThrow(() -> this.imageService.getImageContent(image, owner));
//noinspection DataFlowIssue
final byte[] contentBytes = content.readAllBytes();
assertThat(contentBytes.length, is((int) HAL_LENGTH));
content.close();
}
@Test
public void loadImageWithOwnerAsViewer() throws IOException {
final User owner = this.seedUser();
final Image image = this.seedImage(owner);
final InputStream content = assertDoesNotThrow(() -> this.imageService.getImageContent(image, owner));
//noinspection DataFlowIssue
content.close();
}
@Test
public void loadPublicImage() throws IOException {
final User owner = this.seedUser();
final Image seedImage = this.seedImage(owner);
final Image publicImage = this.makePublic(seedImage, owner);
final InputStream content = assertDoesNotThrow(() -> this.imageService.getImageContent(publicImage, null));
//noinspection DataFlowIssue
content.close();
}
@Test
public void loadImageWithViewer() throws IOException {
final User owner = this.seedUser();
final User viewer = this.seedUser();
Image seedImage = this.seedImage(owner);
final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec();
spec.setViewersToAdd(Set.of(viewer));
final Image imageWithViewer = this.imageService.update(seedImage, owner, spec);
final InputStream content = assertDoesNotThrow(() -> this.imageService.getImageContent(imageWithViewer, viewer));
//noinspection DataFlowIssue
content.close();
}
@Test
public void getImagesOwnedBy() {
final User owner = this.seedUser();
final User otherOwner = this.seedUser();
final Image image0 = this.seedImage(owner);
final Image image1 = this.seedImage(owner);
final Image image2 = this.seedImage(otherOwner);
final List<Image> ownedImages = this.imageService.getImagesOwnedBy(owner);
assertThat(ownedImages.size(), is(2));
assertThat(ownedImages, containsImages(image0, image1));
final List<Image> otherOwnedImages = this.imageService.getImagesOwnedBy(otherOwner);
assertThat(otherOwnedImages.size(), is(1));
assertThat(otherOwnedImages, containsImages(image2));
}
@Test
public void updateAlt() {
final User owner = this.seedUser();
Image image = this.seedImage(owner);
final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec();
spec.setAlt("HAL 9000");
image = this.imageService.update(image, owner, spec);
assertThat(image.getAlt(), is("HAL 9000"));
}
@Test
public void updateCaption() {
final User owner = this.seedUser();
Image image = this.seedImage(owner);
final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec();
spec.setCaption("HAL 9000 from 2001: A Space Odyssey");
image = this.imageService.update(image, owner, spec);
assertThat(image.getCaption(), is("HAL 9000 from 2001: A Space Odyssey"));
}
@Test
public void updateIsPublic() {
final User owner = this.seedUser();
Image image = this.seedImage(owner);
final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec();
spec.setPublic(true);
image = this.imageService.update(image, owner, spec);
assertThat(image.isPublic(), is(true));
}
private Image addViewer(Image image, User owner, User viewer) {
final ImageUpdateInfoSpec spec0 = new ImageUpdateInfoSpec();
spec0.setViewersToAdd(Set.of(viewer));
return this.imageService.update(image, owner, spec0);
}
@Test
public void addViewers() {
final User owner = this.seedUser();
final User viewer = this.seedUser();
Image image = this.seedImage(owner);
image = this.addViewer(image, owner, viewer);
assertThat(image.getViewers(), containsUsers(viewer));
}
@Test
public void removeViewers() {
final User owner = this.seedUser();
final User viewer = this.seedUser();
Image image = this.seedImage(owner);
image = this.addViewer(image, owner, viewer);
assertThat(image.getViewers(), containsUsers(viewer));
final ImageUpdateInfoSpec spec1 = new ImageUpdateInfoSpec();
spec1.setViewersToRemove(Set.of(viewer));
image = this.imageService.update(image, owner, spec1);
assertThat(image.getViewers(), empty());
}
@Test
public void clearAllViewers() {
final User owner = this.seedUser();
final User viewer = this.seedUser();
Image image = this.seedImage(owner);
image = this.addViewer(image, owner, viewer);
assertThat(image.getViewers(), containsUsers(viewer));
final ImageUpdateInfoSpec spec1 = new ImageUpdateInfoSpec();
spec1.setClearAllViewers(true);
image = this.imageService.update(image, owner, spec1);
assertThat(image.getViewers(), empty());
}
@Test
public void deleteImage() throws Exception {
final User owner = this.seedUser();
final Image image = this.seedImage(owner);
this.imageService.deleteImage(image, owner);
assertThrows(ImageException.class, () -> this.imageService.getById(image.getId(), owner));
}
}