mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 11:49:25 +00:00
Unify formatting
This commit is contained in:
@@ -1,35 +1,35 @@
|
||||
package dev.kruhlmann.imgfloat;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import dev.kruhlmann.imgfloat.model.VisibilityRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest(properties = {
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import dev.kruhlmann.imgfloat.model.VisibilityRequest;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@SpringBootTest(
|
||||
properties = {
|
||||
"spring.security.oauth2.client.registration.twitch.client-id=test-client-id",
|
||||
"spring.security.oauth2.client.registration.twitch.client-secret=test-client-secret"
|
||||
})
|
||||
"spring.security.oauth2.client.registration.twitch.client-secret=test-client-secret",
|
||||
}
|
||||
)
|
||||
@AutoConfigureMockMvc
|
||||
class ChannelApiIntegrationTest {
|
||||
|
||||
@@ -42,57 +42,92 @@ class ChannelApiIntegrationTest {
|
||||
@Test
|
||||
void broadcasterManagesAdminsAndAssets() throws Exception {
|
||||
String broadcaster = "caster";
|
||||
mockMvc.perform(post("/api/channels/{broadcaster}/admins", broadcaster)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"username\":\"helper\"}")
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk());
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/channels/{broadcaster}/admins", broadcaster)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"username\":\"helper\"}")
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster)))
|
||||
)
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mockMvc.perform(get("/api/channels/{broadcaster}/admins", broadcaster)
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$[0].login").value("helper"))
|
||||
.andExpect(jsonPath("$[0].displayName").value("helper"));
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/channels/{broadcaster}/admins", broadcaster).with(
|
||||
oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster))
|
||||
)
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$[0].login").value("helper"))
|
||||
.andExpect(jsonPath("$[0].displayName").value("helper"));
|
||||
|
||||
MockMultipartFile file = new MockMultipartFile("file", "image.png", "image/png", samplePng());
|
||||
|
||||
String assetId = objectMapper.readTree(mockMvc.perform(multipart("/api/channels/{broadcaster}/assets", broadcaster)
|
||||
.file(file)
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString()).get("id").asText();
|
||||
String assetId = objectMapper
|
||||
.readTree(
|
||||
mockMvc
|
||||
.perform(
|
||||
multipart("/api/channels/{broadcaster}/assets", broadcaster)
|
||||
.file(file)
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster)))
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andReturn()
|
||||
.getResponse()
|
||||
.getContentAsString()
|
||||
)
|
||||
.get("id")
|
||||
.asText();
|
||||
|
||||
mockMvc.perform(get("/api/channels/{broadcaster}/assets", broadcaster)
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(1)));
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/channels/{broadcaster}/assets", broadcaster).with(
|
||||
oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster))
|
||||
)
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(1)));
|
||||
|
||||
VisibilityRequest visibilityRequest = new VisibilityRequest();
|
||||
visibilityRequest.setHidden(false);
|
||||
mockMvc.perform(put("/api/channels/{broadcaster}/assets/{id}/visibility", broadcaster, assetId)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(visibilityRequest))
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.hidden").value(false));
|
||||
mockMvc
|
||||
.perform(
|
||||
put("/api/channels/{broadcaster}/assets/{id}/visibility", broadcaster, assetId)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(visibilityRequest))
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster)))
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.hidden").value(false));
|
||||
|
||||
mockMvc.perform(get("/api/channels/{broadcaster}/assets/visible", broadcaster)
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(1)));
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/channels/{broadcaster}/assets/visible", broadcaster).with(
|
||||
oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster))
|
||||
)
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(1)));
|
||||
|
||||
mockMvc.perform(delete("/api/channels/{broadcaster}/assets/{id}", broadcaster, assetId)
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", broadcaster))))
|
||||
.andExpect(status().isOk());
|
||||
mockMvc
|
||||
.perform(
|
||||
delete("/api/channels/{broadcaster}/assets/{id}", broadcaster, assetId).with(
|
||||
oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster))
|
||||
)
|
||||
)
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAdminChangesFromNonBroadcaster() throws Exception {
|
||||
mockMvc.perform(post("/api/channels/{broadcaster}/admins", "caster")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"username\":\"helper\"}")
|
||||
.with(oauth2Login().attributes(attrs -> attrs.put("preferred_username", "intruder"))))
|
||||
.andExpect(status().isForbidden());
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/channels/{broadcaster}/admins", "caster")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"username\":\"helper\"}")
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", "intruder")))
|
||||
)
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
private byte[] samplePng() throws IOException {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package dev.kruhlmann.imgfloat;
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import dev.kruhlmann.imgfloat.model.Channel;
|
||||
import dev.kruhlmann.imgfloat.repository.ChannelRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -9,15 +14,12 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest(properties = {
|
||||
@SpringBootTest(
|
||||
properties = {
|
||||
"spring.security.oauth2.client.registration.twitch.client-id=test-client-id",
|
||||
"spring.security.oauth2.client.registration.twitch.client-secret=test-client-secret"
|
||||
})
|
||||
"spring.security.oauth2.client.registration.twitch.client-secret=test-client-secret",
|
||||
}
|
||||
)
|
||||
@AutoConfigureMockMvc
|
||||
class ChannelDirectoryApiIntegrationTest {
|
||||
|
||||
@@ -38,10 +40,11 @@ class ChannelDirectoryApiIntegrationTest {
|
||||
channelRepository.save(new Channel("alpha"));
|
||||
channelRepository.save(new Channel("ALPINE"));
|
||||
|
||||
mockMvc.perform(get("/api/channels").param("q", "Al"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(2)))
|
||||
.andExpect(jsonPath("$[0]").value("alpha"))
|
||||
.andExpect(jsonPath("$[1]").value("alpine"));
|
||||
mockMvc
|
||||
.perform(get("/api/channels").param("q", "Al"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(2)))
|
||||
.andExpect(jsonPath("$[0]").value("alpha"))
|
||||
.andExpect(jsonPath("$[1]").value("alpine"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
package dev.kruhlmann.imgfloat;
|
||||
|
||||
import dev.kruhlmann.imgfloat.model.TransformRequest;
|
||||
import dev.kruhlmann.imgfloat.model.VisibilityRequest;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import dev.kruhlmann.imgfloat.model.Asset;
|
||||
import dev.kruhlmann.imgfloat.model.AssetView;
|
||||
import dev.kruhlmann.imgfloat.model.Channel;
|
||||
import dev.kruhlmann.imgfloat.model.Settings;
|
||||
import dev.kruhlmann.imgfloat.model.TransformRequest;
|
||||
import dev.kruhlmann.imgfloat.model.VisibilityRequest;
|
||||
import dev.kruhlmann.imgfloat.repository.AssetRepository;
|
||||
import dev.kruhlmann.imgfloat.repository.ChannelRepository;
|
||||
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
||||
import dev.kruhlmann.imgfloat.service.AssetStorageService;
|
||||
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
||||
import dev.kruhlmann.imgfloat.service.SettingsService;
|
||||
import dev.kruhlmann.imgfloat.service.media.MediaDetectionService;
|
||||
import dev.kruhlmann.imgfloat.service.media.MediaOptimizationService;
|
||||
import dev.kruhlmann.imgfloat.service.media.MediaPreviewService;
|
||||
import dev.kruhlmann.imgfloat.service.SettingsService;
|
||||
import dev.kruhlmann.imgfloat.model.Settings;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -33,19 +34,17 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
class ChannelDirectoryServiceTest {
|
||||
|
||||
private ChannelDirectoryService service;
|
||||
private SimpMessagingTemplate messagingTemplate;
|
||||
private ChannelRepository channelRepository;
|
||||
@@ -66,8 +65,15 @@ class ChannelDirectoryServiceTest {
|
||||
MediaPreviewService mediaPreviewService = new MediaPreviewService();
|
||||
MediaOptimizationService mediaOptimizationService = new MediaOptimizationService(mediaPreviewService);
|
||||
MediaDetectionService mediaDetectionService = new MediaDetectionService();
|
||||
service = new ChannelDirectoryService(channelRepository, assetRepository, messagingTemplate,
|
||||
assetStorageService, mediaDetectionService, mediaOptimizationService, settingsService);
|
||||
service = new ChannelDirectoryService(
|
||||
channelRepository,
|
||||
assetRepository,
|
||||
messagingTemplate,
|
||||
assetStorageService,
|
||||
mediaDetectionService,
|
||||
mediaOptimizationService,
|
||||
settingsService
|
||||
);
|
||||
ReflectionTestUtils.setField(service, "uploadLimitBytes", 5_000_000L);
|
||||
}
|
||||
|
||||
@@ -78,7 +84,10 @@ class ChannelDirectoryServiceTest {
|
||||
Optional<AssetView> created = service.createAsset("caster", file);
|
||||
assertThat(created).isPresent();
|
||||
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class);
|
||||
verify(messagingTemplate).convertAndSend(org.mockito.ArgumentMatchers.contains("/topic/channel/caster"), captor.capture());
|
||||
verify(messagingTemplate).convertAndSend(
|
||||
org.mockito.ArgumentMatchers.contains("/topic/channel/caster"),
|
||||
captor.capture()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,8 +114,8 @@ class ChannelDirectoryServiceTest {
|
||||
transform.setWidth(0);
|
||||
|
||||
assertThatThrownBy(() -> service.updateTransform(channel, id, transform))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("Canvas width out of range");
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("Canvas width out of range");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -118,15 +127,15 @@ class ChannelDirectoryServiceTest {
|
||||
speedTransform.setSpeed(5.0);
|
||||
|
||||
assertThatThrownBy(() -> service.updateTransform(channel, id, speedTransform))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("Speed out of range");
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("Speed out of range");
|
||||
|
||||
TransformRequest volumeTransform = validTransform();
|
||||
volumeTransform.setAudioVolume(6.5);
|
||||
|
||||
assertThatThrownBy(() -> service.updateTransform(channel, id, volumeTransform))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("Audio volume out of range");
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("Audio volume out of range");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,44 +187,56 @@ class ChannelDirectoryServiceTest {
|
||||
Map<String, Channel> channels = new ConcurrentHashMap<>();
|
||||
Map<String, Asset> assets = new ConcurrentHashMap<>();
|
||||
|
||||
when(channelRepository.findById(anyString()))
|
||||
.thenAnswer(invocation -> Optional.ofNullable(channels.get(invocation.getArgument(0))));
|
||||
when(channelRepository.save(any(Channel.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
Channel channel = invocation.getArgument(0);
|
||||
channels.put(channel.getBroadcaster(), channel);
|
||||
return channel;
|
||||
});
|
||||
when(channelRepository.findAll())
|
||||
.thenAnswer(invocation -> List.copyOf(channels.values()));
|
||||
when(channelRepository.findTop50ByBroadcasterContainingIgnoreCaseOrderByBroadcasterAsc(anyString()))
|
||||
.thenAnswer(invocation -> channels.values().stream()
|
||||
.filter(channel -> Optional.ofNullable(channel.getBroadcaster()).orElse("")
|
||||
.contains(Optional.ofNullable(invocation.getArgument(0, String.class)).orElse("").toLowerCase()))
|
||||
.sorted(Comparator.comparing(Channel::getBroadcaster))
|
||||
.limit(50)
|
||||
.toList());
|
||||
when(channelRepository.findById(anyString())).thenAnswer((invocation) ->
|
||||
Optional.ofNullable(channels.get(invocation.getArgument(0)))
|
||||
);
|
||||
when(channelRepository.save(any(Channel.class))).thenAnswer((invocation) -> {
|
||||
Channel channel = invocation.getArgument(0);
|
||||
channels.put(channel.getBroadcaster(), channel);
|
||||
return channel;
|
||||
});
|
||||
when(channelRepository.findAll()).thenAnswer((invocation) -> List.copyOf(channels.values()));
|
||||
when(channelRepository.findTop50ByBroadcasterContainingIgnoreCaseOrderByBroadcasterAsc(anyString())).thenAnswer(
|
||||
(invocation) ->
|
||||
channels
|
||||
.values()
|
||||
.stream()
|
||||
.filter((channel) ->
|
||||
Optional.ofNullable(channel.getBroadcaster())
|
||||
.orElse("")
|
||||
.contains(
|
||||
Optional.ofNullable(invocation.getArgument(0, String.class)).orElse("").toLowerCase()
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparing(Channel::getBroadcaster))
|
||||
.limit(50)
|
||||
.toList()
|
||||
);
|
||||
|
||||
when(assetRepository.save(any(Asset.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
Asset asset = invocation.getArgument(0);
|
||||
assets.put(asset.getId(), asset);
|
||||
return asset;
|
||||
});
|
||||
when(assetRepository.findById(anyString()))
|
||||
.thenAnswer(invocation -> Optional.ofNullable(assets.get(invocation.getArgument(0))));
|
||||
when(assetRepository.findByBroadcaster(anyString()))
|
||||
.thenAnswer(invocation -> filterAssetsByBroadcaster(assets.values(), invocation.getArgument(0), false));
|
||||
when(assetRepository.findByBroadcasterAndHiddenFalse(anyString()))
|
||||
.thenAnswer(invocation -> filterAssetsByBroadcaster(assets.values(), invocation.getArgument(0), true));
|
||||
doAnswer(invocation -> assets.remove(invocation.getArgument(0, Asset.class).getId()))
|
||||
.when(assetRepository).delete(any(Asset.class));
|
||||
when(assetRepository.save(any(Asset.class))).thenAnswer((invocation) -> {
|
||||
Asset asset = invocation.getArgument(0);
|
||||
assets.put(asset.getId(), asset);
|
||||
return asset;
|
||||
});
|
||||
when(assetRepository.findById(anyString())).thenAnswer((invocation) ->
|
||||
Optional.ofNullable(assets.get(invocation.getArgument(0)))
|
||||
);
|
||||
when(assetRepository.findByBroadcaster(anyString())).thenAnswer((invocation) ->
|
||||
filterAssetsByBroadcaster(assets.values(), invocation.getArgument(0), false)
|
||||
);
|
||||
when(assetRepository.findByBroadcasterAndHiddenFalse(anyString())).thenAnswer((invocation) ->
|
||||
filterAssetsByBroadcaster(assets.values(), invocation.getArgument(0), true)
|
||||
);
|
||||
doAnswer((invocation) -> assets.remove(invocation.getArgument(0, Asset.class).getId()))
|
||||
.when(assetRepository)
|
||||
.delete(any(Asset.class));
|
||||
}
|
||||
|
||||
private List<Asset> filterAssetsByBroadcaster(Collection<Asset> assets, String broadcaster, boolean onlyVisible) {
|
||||
return assets.stream()
|
||||
.filter(asset -> asset.getBroadcaster().equalsIgnoreCase(broadcaster))
|
||||
.filter(asset -> !onlyVisible || !asset.isHidden())
|
||||
.toList();
|
||||
return assets
|
||||
.stream()
|
||||
.filter((asset) -> asset.getBroadcaster().equalsIgnoreCase(broadcaster))
|
||||
.filter((asset) -> !onlyVisible || !asset.isHidden())
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package dev.kruhlmann.imgfloat.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
@@ -12,39 +14,43 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResp
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TwitchAuthorizationCodeGrantRequestEntityConverterTest {
|
||||
|
||||
@Test
|
||||
void addsClientIdAndSecretToTokenRequestBody() {
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId("twitch")
|
||||
.clientId("twitch-id")
|
||||
.clientSecret("twitch-secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("https://example.com/redirect")
|
||||
.scope("user:read:email")
|
||||
.authorizationUri("https://id.twitch.tv/oauth2/authorize")
|
||||
.tokenUri("https://id.twitch.tv/oauth2/token")
|
||||
.userInfoUri("https://api.twitch.tv/helix/users")
|
||||
.userNameAttributeName("preferred_username")
|
||||
.build();
|
||||
.clientId("twitch-id")
|
||||
.clientSecret("twitch-secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.redirectUri("https://example.com/redirect")
|
||||
.scope("user:read:email")
|
||||
.authorizationUri("https://id.twitch.tv/oauth2/authorize")
|
||||
.tokenUri("https://id.twitch.tv/oauth2/token")
|
||||
.userInfoUri("https://api.twitch.tv/helix/users")
|
||||
.userNameAttributeName("preferred_username")
|
||||
.build();
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri(registration.getProviderDetails().getAuthorizationUri())
|
||||
.clientId(registration.getClientId())
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.state("state")
|
||||
.build();
|
||||
.authorizationUri(registration.getProviderDetails().getAuthorizationUri())
|
||||
.clientId(registration.getClientId())
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.state("state")
|
||||
.build();
|
||||
|
||||
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponse.success("code")
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.state("state")
|
||||
.build();
|
||||
.redirectUri(registration.getRedirectUri())
|
||||
.state("state")
|
||||
.build();
|
||||
|
||||
OAuth2AuthorizationExchange exchange = new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse);
|
||||
OAuth2AuthorizationCodeGrantRequest grantRequest = new OAuth2AuthorizationCodeGrantRequest(registration, exchange);
|
||||
OAuth2AuthorizationExchange exchange = new OAuth2AuthorizationExchange(
|
||||
authorizationRequest,
|
||||
authorizationResponse
|
||||
);
|
||||
OAuth2AuthorizationCodeGrantRequest grantRequest = new OAuth2AuthorizationCodeGrantRequest(
|
||||
registration,
|
||||
exchange
|
||||
);
|
||||
|
||||
var converter = new TwitchAuthorizationCodeGrantRequestEntityConverter();
|
||||
RequestEntity<?> requestEntity = converter.convert(grantRequest);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package dev.kruhlmann.imgfloat.config;
|
||||
|
||||
import java.net.URI;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||
|
||||
import java.net.URI;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -13,11 +17,6 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenRespon
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||
|
||||
class TwitchOAuth2ErrorResponseErrorHandlerTest {
|
||||
|
||||
private final TwitchOAuth2ErrorResponseErrorHandler handler = new TwitchOAuth2ErrorResponseErrorHandler();
|
||||
@@ -27,12 +26,12 @@ class TwitchOAuth2ErrorResponseErrorHandlerTest {
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(new byte[0], HttpStatus.BAD_REQUEST);
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
OAuth2AuthorizationException exception = assertThrows(OAuth2AuthorizationException.class,
|
||||
() -> handler.handleError(response));
|
||||
OAuth2AuthorizationException exception = assertThrows(OAuth2AuthorizationException.class, () ->
|
||||
handler.handleError(response)
|
||||
);
|
||||
|
||||
assertThat(exception.getError().getErrorCode()).isEqualTo("invalid_token_response");
|
||||
assertThat(exception.getError().getDescription())
|
||||
.contains("Failed to parse Twitch OAuth error response");
|
||||
assertThat(exception.getError().getDescription()).contains("Failed to parse Twitch OAuth error response");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -41,13 +40,20 @@ class TwitchOAuth2ErrorResponseErrorHandlerTest {
|
||||
restTemplate.setErrorHandler(new TwitchOAuth2ErrorResponseErrorHandler());
|
||||
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
|
||||
|
||||
server.expect(requestTo("https://id.twitch.tv/oauth2/token"))
|
||||
.andRespond(withSuccess(
|
||||
"{\"access_token\":\"abc\",\"token_type\":\"bearer\",\"expires_in\":3600,\"scope\":[]}",
|
||||
MediaType.APPLICATION_JSON));
|
||||
server
|
||||
.expect(requestTo("https://id.twitch.tv/oauth2/token"))
|
||||
.andRespond(
|
||||
withSuccess(
|
||||
"{\"access_token\":\"abc\",\"token_type\":\"bearer\",\"expires_in\":3600,\"scope\":[]}",
|
||||
MediaType.APPLICATION_JSON
|
||||
)
|
||||
);
|
||||
|
||||
RequestEntity<Void> request = RequestEntity.post(URI.create("https://id.twitch.tv/oauth2/token")).build();
|
||||
ResponseEntity<OAuth2AccessTokenResponse> response = restTemplate.exchange(request, OAuth2AccessTokenResponse.class);
|
||||
ResponseEntity<OAuth2AccessTokenResponse> response = restTemplate.exchange(
|
||||
request,
|
||||
OAuth2AccessTokenResponse.class
|
||||
);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getBody()).isNotNull();
|
||||
|
||||
@@ -8,7 +8,6 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -26,51 +25,54 @@ class TwitchOAuth2UserServiceTest {
|
||||
@Test
|
||||
void unwrapsTwitchUserAndAddsClientIdHeaderToUserInfoRequest() {
|
||||
ClientRegistration registration = twitchRegistrationBuilder()
|
||||
.clientId("client-123")
|
||||
.clientSecret("secret")
|
||||
.build();
|
||||
.clientId("client-123")
|
||||
.clientSecret("secret")
|
||||
.build();
|
||||
|
||||
OAuth2UserRequest userRequest = userRequest(registration);
|
||||
RestTemplate restTemplate = TwitchOAuth2UserService.createRestTemplate(userRequest);
|
||||
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
|
||||
|
||||
TwitchOAuth2UserService service = new TwitchOAuth2UserService(ignored -> restTemplate);
|
||||
TwitchOAuth2UserService service = new TwitchOAuth2UserService((ignored) -> restTemplate);
|
||||
|
||||
server.expect(requestTo("https://api.twitch.tv/helix/users"))
|
||||
.andExpect(method(HttpMethod.GET))
|
||||
.andExpect(header("Client-ID", "client-123"))
|
||||
.andRespond(withSuccess(
|
||||
"{\"data\":[{\"id\":\"42\",\"login\":\"demo\",\"display_name\":\"Demo\"}]}",
|
||||
MediaType.APPLICATION_JSON));
|
||||
server
|
||||
.expect(requestTo("https://api.twitch.tv/helix/users"))
|
||||
.andExpect(method(HttpMethod.GET))
|
||||
.andExpect(header("Client-ID", "client-123"))
|
||||
.andRespond(
|
||||
withSuccess(
|
||||
"{\"data\":[{\"id\":\"42\",\"login\":\"demo\",\"display_name\":\"Demo\"}]}",
|
||||
MediaType.APPLICATION_JSON
|
||||
)
|
||||
);
|
||||
|
||||
OAuth2User user = service.loadUser(userRequest);
|
||||
|
||||
assertThat(user.getName()).isEqualTo("demo");
|
||||
assertThat(user.getAttributes())
|
||||
.containsEntry("id", "42")
|
||||
.containsEntry("display_name", "Demo");
|
||||
assertThat(user.getAttributes()).containsEntry("id", "42").containsEntry("display_name", "Demo");
|
||||
server.verify();
|
||||
}
|
||||
|
||||
private OAuth2UserRequest userRequest(ClientRegistration registration) {
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER,
|
||||
"token",
|
||||
Instant.now(),
|
||||
Instant.now().plusSeconds(60),
|
||||
Set.of("user:read:email"));
|
||||
OAuth2AccessToken.TokenType.BEARER,
|
||||
"token",
|
||||
Instant.now(),
|
||||
Instant.now().plusSeconds(60),
|
||||
Set.of("user:read:email")
|
||||
);
|
||||
return new OAuth2UserRequest(registration, accessToken);
|
||||
}
|
||||
|
||||
private ClientRegistration.Builder twitchRegistrationBuilder() {
|
||||
return ClientRegistration.withRegistrationId("twitch")
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
|
||||
.clientName("Twitch")
|
||||
.redirectUri("https://example.com/login/oauth2/code/twitch")
|
||||
.authorizationUri("https://id.twitch.tv/oauth2/authorize")
|
||||
.tokenUri("https://id.twitch.tv/oauth2/token")
|
||||
.userInfoUri("https://api.twitch.tv/helix/users")
|
||||
.userNameAttributeName("login");
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
|
||||
.clientName("Twitch")
|
||||
.redirectUri("https://example.com/login/oauth2/code/twitch")
|
||||
.authorizationUri("https://id.twitch.tv/oauth2/authorize")
|
||||
.tokenUri("https://id.twitch.tv/oauth2/token")
|
||||
.userInfoUri("https://api.twitch.tv/helix/users")
|
||||
.userNameAttributeName("login");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package dev.kruhlmann.imgfloat.service;
|
||||
|
||||
import dev.kruhlmann.imgfloat.service.media.AssetContent;
|
||||
import dev.kruhlmann.imgfloat.model.Asset;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import dev.kruhlmann.imgfloat.model.Asset;
|
||||
import dev.kruhlmann.imgfloat.service.media.AssetContent;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AssetStorageServiceTest {
|
||||
|
||||
private AssetStorageService service;
|
||||
private Path assets;
|
||||
private Path previews;
|
||||
@@ -27,13 +27,13 @@ class AssetStorageServiceTest {
|
||||
@Test
|
||||
void refusesToStoreEmptyAsset() {
|
||||
assertThatThrownBy(() -> service.storeAsset("caster", "id", new byte[0], "image/png"))
|
||||
.isInstanceOf(IOException.class)
|
||||
.hasMessageContaining("empty");
|
||||
.isInstanceOf(IOException.class)
|
||||
.hasMessageContaining("empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
void storesAndLoadsAssets() throws IOException {
|
||||
byte[] bytes = new byte[]{1, 2, 3};
|
||||
byte[] bytes = new byte[] { 1, 2, 3 };
|
||||
Asset asset = new Asset("caster", "asset", "http://example.com", 10, 10);
|
||||
asset.setMediaType("image/png");
|
||||
|
||||
@@ -53,7 +53,7 @@ class AssetStorageServiceTest {
|
||||
|
||||
@Test
|
||||
void storesAndLoadsPreviews() throws IOException {
|
||||
byte[] preview = new byte[]{9, 8, 7};
|
||||
byte[] preview = new byte[] { 9, 8, 7 };
|
||||
Asset asset = new Asset("caster", "asset", "http://example.com", 10, 10);
|
||||
asset.setMediaType("image/png");
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package dev.kruhlmann.imgfloat.service.media;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
class MediaDetectionServiceTest {
|
||||
|
||||
private final MediaDetectionService service = new MediaDetectionService();
|
||||
|
||||
@Test
|
||||
void acceptsMagicBytesOverDeclaredType() throws IOException {
|
||||
byte[] png = new byte[]{(byte) 0x89, 0x50, 0x4E, 0x47};
|
||||
byte[] png = new byte[] { (byte) 0x89, 0x50, 0x4E, 0x47 };
|
||||
MockMultipartFile file = new MockMultipartFile("file", "image.png", "text/plain", png);
|
||||
|
||||
assertThat(service.detectAllowedMediaType(file, file.getBytes())).contains("image/png");
|
||||
@@ -20,14 +20,14 @@ class MediaDetectionServiceTest {
|
||||
|
||||
@Test
|
||||
void fallsBackToFilenameAllowlist() throws IOException {
|
||||
MockMultipartFile file = new MockMultipartFile("file", "picture.png", null, new byte[]{1, 2, 3});
|
||||
MockMultipartFile file = new MockMultipartFile("file", "picture.png", null, new byte[] { 1, 2, 3 });
|
||||
|
||||
assertThat(service.detectAllowedMediaType(file, file.getBytes())).contains("image/png");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsUnknownTypes() throws IOException {
|
||||
MockMultipartFile file = new MockMultipartFile("file", "unknown.bin", null, new byte[]{1, 2, 3});
|
||||
MockMultipartFile file = new MockMultipartFile("file", "unknown.bin", null, new byte[] { 1, 2, 3 });
|
||||
|
||||
assertThat(service.detectAllowedMediaType(file, file.getBytes())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package dev.kruhlmann.imgfloat.service.media;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MediaOptimizationServiceTest {
|
||||
|
||||
private MediaOptimizationService service;
|
||||
|
||||
@BeforeEach
|
||||
@@ -38,7 +38,7 @@ class MediaOptimizationServiceTest {
|
||||
|
||||
@Test
|
||||
void returnsNullForUnsupportedBytes() throws IOException {
|
||||
OptimizedAsset optimized = service.optimizeAsset(new byte[]{1, 2, 3}, "application/octet-stream");
|
||||
OptimizedAsset optimized = service.optimizeAsset(new byte[] { 1, 2, 3 }, "application/octet-stream");
|
||||
|
||||
assertThat(optimized).isNull();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user