use 120 max line length for both server and client code (was 100 and 140)

This commit is contained in:
Athou
2026-11-03 06:48:11 +01:00
parent 29987a460d
commit 69cf674a02
157 changed files with 1228 additions and 1958 deletions

View File

@@ -25,26 +25,14 @@ class NativeImageClassesTest {
void annotationContainsAllRequiredRomeClasses() {
Reflections reflections = new Reflections("com.rometools");
Set<Class<?>> classesInAnnotation =
Set.copyOf(
List.of(
NativeImageClasses.class
.getAnnotation(RegisterForReflection.class)
.targets()));
Set.copyOf(List.of(NativeImageClasses.class.getAnnotation(RegisterForReflection.class).targets()));
List<Class<?>> missingClasses = new ArrayList<>();
for (Class<?> clazz :
List.of(
Module.class,
Cloneable.class,
CopyFrom.class,
WireFeedParser.class,
WireFeedGenerator.class)) {
Set<Class<?>> moduleClasses =
new HashSet<>(reflections.get(Scanners.SubTypes.of(clazz).asClass()));
List.of(Module.class, Cloneable.class, CopyFrom.class, WireFeedParser.class, WireFeedGenerator.class)) {
Set<Class<?>> moduleClasses = new HashSet<>(reflections.get(Scanners.SubTypes.of(clazz).asClass()));
moduleClasses.removeIf(c ->
c.isInterface()
|| Modifier.isAbstract(c.getModifiers())
|| !Modifier.isPublic(c.getModifiers()));
c.isInterface() || Modifier.isAbstract(c.getModifiers()) || !Modifier.isPublic(c.getModifiers()));
moduleClasses.removeAll(classesInAnnotation);
missingClasses.addAll(moduleClasses);
}

View File

@@ -7,8 +7,7 @@ class DigestsTest {
@Test
void sha1Hex() {
Assertions.assertEquals(
"aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", Digests.sha1Hex("hello"));
Assertions.assertEquals("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", Digests.sha1Hex("hello"));
}
@Test

View File

@@ -65,9 +65,7 @@ class HttpGetterTest {
void init() throws IOException {
this.mockServerClient = ClientAndServer.startClientAndServer(0);
this.feedUrl = "http://localhost:" + this.mockServerClient.getPort() + "/";
this.feedContent =
IOUtils.toByteArray(
Objects.requireNonNull(getClass().getResource("/feed/rss.xml")));
this.feedContent = IOUtils.toByteArray(Objects.requireNonNull(getClass().getResource("/feed/rss.xml")));
this.config = Mockito.mock(CommaFeedConfiguration.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(config.httpClient().userAgent()).thenReturn(Optional.of("http-getter-test"));
@@ -78,14 +76,12 @@ class HttpGetterTest {
Mockito.when(config.httpClient().connectionTimeToLive()).thenReturn(Duration.ofSeconds(30));
Mockito.when(config.httpClient().maxResponseSize()).thenReturn(MemorySize.of("10000"));
Mockito.when(config.httpClient().cache().enabled()).thenReturn(true);
Mockito.when(config.httpClient().cache().maximumMemorySize())
.thenReturn(MemorySize.of("100000"));
Mockito.when(config.httpClient().cache().maximumMemorySize()).thenReturn(MemorySize.of("100000"));
Mockito.when(config.httpClient().cache().expiration()).thenReturn(Duration.ofMinutes(1));
Mockito.when(config.feedRefresh().httpThreads()).thenReturn(3);
this.provider = new HttpClientFactory(config, Mockito.mock(CommaFeedVersion.class));
this.getter =
new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
this.getter = new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
}
@AfterEach
@@ -108,9 +104,7 @@ class HttpGetterTest {
.when(HttpRequest.request().withMethod("GET"))
.respond(HttpResponse.response().withStatusCode(code));
HttpResponseException e =
Assertions.assertThrows(
HttpResponseException.class, () -> getter.get(this.feedUrl));
HttpResponseException e = Assertions.assertThrows(HttpResponseException.class, () -> getter.get(this.feedUrl));
Assertions.assertEquals(code, e.getCode());
}
@@ -124,8 +118,7 @@ class HttpGetterTest {
.withContentType(MediaType.APPLICATION_ATOM_XML)
.withHeader(HttpHeaders.LAST_MODIFIED, "123456")
.withHeader(HttpHeaders.ETAG, "78910")
.withHeader(
HttpHeaders.CACHE_CONTROL, "max-age=60, must-revalidate")
.withHeader(HttpHeaders.CACHE_CONTROL, "max-age=60, must-revalidate")
.withHeader(HttpHeaders.RETRY_AFTER, "120"));
HttpResult result = getter.get(this.feedUrl);
@@ -145,8 +138,7 @@ class HttpGetterTest {
HttpResponse.response()
.withBody(feedContent)
.withContentType(MediaType.APPLICATION_ATOM_XML)
.withHeader(
HttpHeaders.CACHE_CONTROL, "max-age=60; must-revalidate"));
.withHeader(HttpHeaders.CACHE_CONTROL, "max-age=60; must-revalidate"));
HttpResult result = getter.get(this.feedUrl);
Assertions.assertEquals(Duration.ZERO, result.validFor());
@@ -162,8 +154,7 @@ class HttpGetterTest {
.withHeader(HttpHeaders.RETRY_AFTER, "120"));
TooManyRequestsException e =
Assertions.assertThrows(
TooManyRequestsException.class, () -> getter.get(this.feedUrl));
Assertions.assertThrows(TooManyRequestsException.class, () -> getter.get(this.feedUrl));
Assertions.assertEquals(NOW.plusSeconds(120), e.getRetryAfter());
}
@@ -174,12 +165,10 @@ class HttpGetterTest {
.respond(
HttpResponse.response()
.withStatusCode(HttpStatus.SC_TOO_MANY_REQUESTS)
.withHeader(
HttpHeaders.RETRY_AFTER, "Wed, 21 Oct 2015 07:28:00 GMT"));
.withHeader(HttpHeaders.RETRY_AFTER, "Wed, 21 Oct 2015 07:28:00 GMT"));
TooManyRequestsException e =
Assertions.assertThrows(
TooManyRequestsException.class, () -> getter.get(this.feedUrl));
Assertions.assertThrows(TooManyRequestsException.class, () -> getter.get(this.feedUrl));
Assertions.assertEquals(Instant.parse("2015-10-21T07:28:00Z"), e.getRetryAfter());
}
@@ -200,9 +189,7 @@ class HttpGetterTest {
.withStatusCode(code)
.withHeader(
HttpHeaders.LOCATION,
"http://localhost:"
+ this.mockServerClient.getPort()
+ "/redirected"));
"http://localhost:" + this.mockServerClient.getPort() + "/redirected"));
// second redirect
this.mockServerClient
@@ -212,29 +199,22 @@ class HttpGetterTest {
.withStatusCode(code)
.withHeader(
HttpHeaders.LOCATION,
"http://localhost:"
+ this.mockServerClient.getPort()
+ "/redirected-2"));
"http://localhost:" + this.mockServerClient.getPort() + "/redirected-2"));
// final destination
this.mockServerClient
.when(HttpRequest.request().withMethod("GET").withPath("/redirected-2"))
.respond(
HttpResponse.response()
.withBody(feedContent)
.withContentType(MediaType.APPLICATION_ATOM_XML));
.respond(HttpResponse.response().withBody(feedContent).withContentType(MediaType.APPLICATION_ATOM_XML));
HttpResult result = getter.get(this.feedUrl);
Assertions.assertEquals(
"http://localhost:" + this.mockServerClient.getPort() + "/redirected-2",
result.urlAfterRedirect());
"http://localhost:" + this.mockServerClient.getPort() + "/redirected-2", result.urlAfterRedirect());
}
@Test
void dataTimeout() {
Mockito.when(config.httpClient().responseTimeout()).thenReturn(Duration.ofMillis(500));
this.getter =
new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
this.getter = new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
this.mockServerClient
.when(HttpRequest.request().withMethod("GET"))
@@ -246,29 +226,23 @@ class HttpGetterTest {
@Test
void connectTimeout() {
Mockito.when(config.httpClient().connectTimeout()).thenReturn(Duration.ofMillis(500));
this.getter =
new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
this.getter = new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
// try to connect to a non-routable address
// https://stackoverflow.com/a/904609
Exception e =
Assertions.assertThrows(Exception.class, () -> getter.get("http://10.255.255.1"));
Exception e = Assertions.assertThrows(Exception.class, () -> getter.get("http://10.255.255.1"));
Assertions.assertTrue(
e instanceof ConnectTimeoutException
// A NoRouteToHostException can also be thrown in some cases
// depending on the underlying network configuration
// https://github.com/Athou/commafeed/issues/1876
|| e instanceof NoRouteToHostException,
"Expected ConnectTimeoutException or NoRouteToHostException, but got: "
+ e.getClass().getName());
"Expected ConnectTimeoutException or NoRouteToHostException, but got: " + e.getClass().getName());
}
@Test
void userAgent() throws Exception {
this.mockServerClient
.when(
HttpRequest.request()
.withMethod("GET")
.withHeader(HttpHeaders.USER_AGENT, "http-getter-test"))
.when(HttpRequest.request().withMethod("GET").withHeader(HttpHeaders.USER_AGENT, "http-getter-test"))
.respond(HttpResponse.response().withBody("ok"));
HttpResult result = getter.get(this.feedUrl);
@@ -278,37 +252,23 @@ class HttpGetterTest {
@Test
void lastModifiedReturns304() {
this.mockServerClient
.when(
HttpRequest.request()
.withMethod("GET")
.withHeader(HttpHeaders.IF_MODIFIED_SINCE, "123456"))
.when(HttpRequest.request().withMethod("GET").withHeader(HttpHeaders.IF_MODIFIED_SINCE, "123456"))
.respond(HttpResponse.response().withStatusCode(HttpStatus.SC_NOT_MODIFIED));
Assertions.assertThrows(
NotModifiedException.class,
() ->
getter.get(
HttpGetter.HttpRequest.builder(this.feedUrl)
.lastModified("123456")
.build()));
() -> getter.get(HttpGetter.HttpRequest.builder(this.feedUrl).lastModified("123456").build()));
}
@Test
void eTagReturns304() {
this.mockServerClient
.when(
HttpRequest.request()
.withMethod("GET")
.withHeader(HttpHeaders.IF_NONE_MATCH, "78910"))
.when(HttpRequest.request().withMethod("GET").withHeader(HttpHeaders.IF_NONE_MATCH, "78910"))
.respond(HttpResponse.response().withStatusCode(HttpStatus.SC_NOT_MODIFIED));
Assertions.assertThrows(
NotModifiedException.class,
() ->
getter.get(
HttpGetter.HttpRequest.builder(this.feedUrl)
.eTag("78910")
.build()));
() -> getter.get(HttpGetter.HttpRequest.builder(this.feedUrl).eTag("78910").build()));
}
@Test
@@ -324,9 +284,7 @@ class HttpGetterTest {
throw new Exception("cookie should not be sent by the client");
}
return HttpResponse.response()
.withBody("ok")
.withHeader(HttpHeaders.SET_COOKIE, "foo=bar");
return HttpResponse.response().withBody("ok").withHeader(HttpHeaders.SET_COOKIE, "foo=bar");
});
Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl));
@@ -360,8 +318,7 @@ class HttpGetterTest {
IOException e = Assertions.assertThrows(IOException.class, () -> getter.get(this.feedUrl));
Assertions.assertEquals(
"Response size (100000 bytes) exceeds the maximum allowed size (10000 bytes)",
e.getMessage());
"Response size (100000 bytes) exceeds the maximum allowed size (10000 bytes)", e.getMessage());
}
@Test
@@ -374,12 +331,10 @@ class HttpGetterTest {
HttpResponse.response()
.withBody(bytes)
.withConnectionOptions(
ConnectionOptions.connectionOptions()
.withSuppressContentLengthHeader(true)));
ConnectionOptions.connectionOptions().withSuppressContentLengthHeader(true)));
IOException e = Assertions.assertThrows(IOException.class, () -> getter.get(this.feedUrl));
Assertions.assertEquals(
"Response size exceeds the maximum allowed size (10000 bytes)", e.getMessage());
Assertions.assertEquals("Response size exceeds the maximum allowed size (10000 bytes)", e.getMessage());
}
@Test
@@ -427,8 +382,7 @@ class HttpGetterTest {
supportsCompression("deflate", DeflaterOutputStream::new);
}
void supportsCompression(String encoding, CompressionFunction compressionFunction)
throws Exception {
void supportsCompression(String encoding, CompressionFunction compressionFunction) throws Exception {
String body = "my body";
HttpGetterTest.this
@@ -436,8 +390,7 @@ class HttpGetterTest {
.when(HttpRequest.request().withMethod("GET"))
.respond(req -> {
try {
String acceptEncodingHeader =
req.getFirstHeader(HttpHeaders.ACCEPT_ENCODING);
String acceptEncodingHeader = req.getFirstHeader(HttpHeaders.ACCEPT_ENCODING);
if (!ACCEPT_ENCODING.equals(acceptEncodingHeader)) {
throw new Exception(
"Wrong value in the Accept-Encoding header, should be '%s' but was '%s'"
@@ -445,8 +398,7 @@ class HttpGetterTest {
}
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (OutputStream compressionOutputStream =
compressionFunction.apply(output)) {
try (OutputStream compressionOutputStream = compressionFunction.apply(output)) {
compressionOutputStream.write(body.getBytes());
}
@@ -473,16 +425,12 @@ class HttpGetterTest {
class SchemeNotAllowed {
@Test
void file() {
Assertions.assertThrows(
HttpGetter.SchemeNotAllowedException.class,
() -> getter.get("file://localhost"));
Assertions.assertThrows(HttpGetter.SchemeNotAllowedException.class, () -> getter.get("file://localhost"));
}
@Test
void ftp() {
Assertions.assertThrows(
HttpGetter.SchemeNotAllowedException.class,
() -> getter.get("ftp://localhost"));
Assertions.assertThrows(HttpGetter.SchemeNotAllowedException.class, () -> getter.get("ftp://localhost"));
}
}
@@ -492,20 +440,15 @@ class HttpGetterTest {
@BeforeEach
void init() {
Mockito.when(config.httpClient().blockLocalAddresses()).thenReturn(true);
getter =
new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
getter = new HttpGetter(config, () -> NOW, provider, Mockito.mock(MetricRegistry.class));
}
@Test
void localhost() {
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://localhost"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://127.0.0.1"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://2130706433"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://0x7F.0x00.0x00.0X01"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://localhost"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://127.0.0.1"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://2130706433"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://0x7F.0x00.0x00.0X01"));
}
@Test
@@ -515,72 +458,54 @@ class HttpGetterTest {
@Test
void linkLocal() {
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://169.254.12.34"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://169.254.169.254"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://169.254.12.34"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://169.254.169.254"));
}
@Test
void multicast() {
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://224.2.3.4"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://239.255.255.254"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://224.2.3.4"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://239.255.255.254"));
}
@Test
void privateIpv4Ranges() {
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://10.0.0.1"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://172.16.0.1"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://192.168.0.1"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://100.64.0.1"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://10.0.0.1"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://172.16.0.1"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://192.168.0.1"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://100.64.0.1"));
}
@Test
void privateIpv6Ranges() {
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[fe80::215:5dff:fe15:102]"));
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://[fd00:dead:beef::50]"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://[fe80::215:5dff:fe15:102]"));
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://[fd00:dead:beef::50]"));
}
@Test
void nat64() {
// 64:ff9b::/96 embeds the IPv4 address in the lower 32 bits (RFC 6052)
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[64:ff9b::a9fe:a9fe]")); // 169.254.169.254
UnknownHostException.class, () -> getter.get("http://[64:ff9b::a9fe:a9fe]")); // 169.254.169.254
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[64:ff9b::a00:1]")); // 10.0.0.1
UnknownHostException.class, () -> getter.get("http://[64:ff9b::a00:1]")); // 10.0.0.1
}
@Test
void nat64LocalUse() {
// 64:ff9b:1::/48 is reserved for local use (RFC 8215), the whole range is blocked
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[64:ff9b:1::a9fe:a9fe]")); // 169.254.169.254
UnknownHostException.class, () -> getter.get("http://[64:ff9b:1::a9fe:a9fe]")); // 169.254.169.254
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[64:ff9b:1:ffff::a00:1]")); // 10.0.0.1
UnknownHostException.class, () -> getter.get("http://[64:ff9b:1:ffff::a00:1]")); // 10.0.0.1
}
@Test
void sixToFour() {
// 2002::/16 embeds the IPv4 address in bits 16-47 (RFC 3056)
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[2002:a9fe:a9fe::]")); // 169.254.169.254
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[2002:a00:1::]")); // 10.0.0.1
UnknownHostException.class, () -> getter.get("http://[2002:a9fe:a9fe::]")); // 169.254.169.254
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://[2002:a00:1::]")); // 10.0.0.1
}
@Test
@@ -597,10 +522,8 @@ class HttpGetterTest {
// deprecated ::/96 IPv4-compatible addresses embed the IPv4 address in the lower 32
// bits
Assertions.assertThrows(
UnknownHostException.class,
() -> getter.get("http://[::a9fe:a9fe]")); // 169.254.169.254
Assertions.assertThrows(
UnknownHostException.class, () -> getter.get("http://[::a00:1]")); // 10.0.0.1
UnknownHostException.class, () -> getter.get("http://[::a9fe:a9fe]")); // 169.254.169.254
Assertions.assertThrows(UnknownHostException.class, () -> getter.get("http://[::a00:1]")); // 10.0.0.1
}
}

View File

@@ -50,25 +50,17 @@ class UrlsTest {
// usual cases
Assertions.assertEquals(
expected,
Urls.toAbsolute(
"http://a.com/blog/entry/1", "http://a.com/feed/", "http://a.com/feed/"));
expected, Urls.toAbsolute("http://a.com/blog/entry/1", "http://a.com/feed/", "http://a.com/feed/"));
Assertions.assertEquals(
expected,
Urls.toAbsolute(
"http://a.com/blog/entry/1", "http://a.com/feed", "http://a.com/feed"));
expected, Urls.toAbsolute("http://a.com/blog/entry/1", "http://a.com/feed", "http://a.com/feed"));
// relative links
Assertions.assertEquals(
expected,
Urls.toAbsolute("../blog/entry/1", "http://a.com/feed/", "http://a.com/feed/"));
Assertions.assertEquals(
expected,
Urls.toAbsolute("../blog/entry/1", "feed.xml", "http://a.com/feed/feed.xml"));
expected, Urls.toAbsolute("../blog/entry/1", "http://a.com/feed/", "http://a.com/feed/"));
Assertions.assertEquals(expected, Urls.toAbsolute("../blog/entry/1", "feed.xml", "http://a.com/feed/feed.xml"));
// root-relative links
Assertions.assertEquals(
expected, Urls.toAbsolute("/blog/entry/1", "/feed", "http://a.com/feed"));
Assertions.assertEquals(expected, Urls.toAbsolute("/blog/entry/1", "/feed", "http://a.com/feed"));
// real cases
Assertions.assertEquals(
@@ -79,10 +71,7 @@ class UrlsTest {
"https://github.com/erusev/parsedown/tags.atom"));
Assertions.assertEquals(
"http://ergoemacs.org/emacs/elisp_all_about_lines.html",
Urls.toAbsolute(
"elisp_all_about_lines.html",
"blog.xml",
"http://ergoemacs.org/emacs/blog.xml"));
Urls.toAbsolute("elisp_all_about_lines.html", "blog.xml", "http://ergoemacs.org/emacs/blog.xml"));
// invalid relative urls
Assertions.assertEquals(
@@ -97,13 +86,11 @@ class UrlsTest {
void testSanitize() {
// valid http/https urls are kept as is
Assertions.assertEquals("http://example.com/foo", Urls.sanitize("http://example.com/foo"));
Assertions.assertEquals(
"https://example.com/foo", Urls.sanitize("https://example.com/foo"));
Assertions.assertEquals("https://example.com/foo", Urls.sanitize("https://example.com/foo"));
// scheme matching is case-insensitive
Assertions.assertEquals("HTTP://example.com/foo", Urls.sanitize("HTTP://example.com/foo"));
Assertions.assertEquals(
"HTTPS://example.com/foo", Urls.sanitize("HTTPS://example.com/foo"));
Assertions.assertEquals("HTTPS://example.com/foo", Urls.sanitize("HTTPS://example.com/foo"));
// malicious or disallowed schemes are stripped
Assertions.assertNull(Urls.sanitize("javascript:alert(1)"));

View File

@@ -36,11 +36,8 @@ class FacebookFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/png";
HttpResult httpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(
httpGetter.get(
"https://graph.facebook.com/validUserId/picture?type=square&height=16"))
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://graph.facebook.com/validUserId/picture?type=square&height=16"))
.thenReturn(httpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -73,9 +70,7 @@ class FacebookFaviconFetcherTest {
Feed feed = new Feed();
feed.setUrl("https://www.facebook.com/something?id=validUserId");
Mockito.when(
httpGetter.get(
"https://graph.facebook.com/validUserId/picture?type=square&height=16"))
Mockito.when(httpGetter.get("https://graph.facebook.com/validUserId/picture?type=square&height=16"))
.thenThrow(new RuntimeException("Network error"));
Assertions.assertNull(faviconFetcher.fetch(feed));

View File

@@ -45,8 +45,7 @@ class FeedFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/png";
HttpResult httpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenReturn(httpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -62,8 +61,7 @@ class FeedFaviconFetcherTest {
feed.setUrl("https://example.com/feed");
feed.setIconUrl("https://example.com/icon.png");
Mockito.when(httpGetter.get("https://example.com/icon.png"))
.thenThrow(new RuntimeException("Network error"));
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenThrow(new RuntimeException("Network error"));
Assertions.assertNull(faviconFetcher.fetch(feed));
}

View File

@@ -43,16 +43,13 @@ class HtmlFaviconFetcherTest {
feed.setUrl("https://example.com/feed");
feed.setLink("https://example.com");
String html =
"<html><head><link rel=\"icon\" href=\"/favicon.png\" /></head><body></body></html>";
HttpResult pageResult =
new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
String html = "<html><head><link rel=\"icon\" href=\"/favicon.png\" /></head><body></body></html>";
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
byte[] iconBytes = new byte[1000];
String contentType = "image/png";
HttpResult iconResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult iconResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/favicon.png")).thenReturn(iconResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -70,16 +67,13 @@ class HtmlFaviconFetcherTest {
String html =
"<html><head><link rel=\"shortcut icon\" href=\"https://example.com/shortcut-favicon.ico\" /></head><body></body></html>";
HttpResult pageResult =
new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
byte[] iconBytes = new byte[1000];
String contentType = "image/x-icon";
HttpResult iconResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/shortcut-favicon.ico"))
.thenReturn(iconResult);
HttpResult iconResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/shortcut-favicon.ico")).thenReturn(iconResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -95,8 +89,7 @@ class HtmlFaviconFetcherTest {
feed.setLink("https://example.com");
String html = "<html><head></head><body></body></html>";
HttpResult pageResult =
new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
Assertions.assertNull(faviconFetcher.fetch(feed));
@@ -108,8 +101,7 @@ class HtmlFaviconFetcherTest {
feed.setUrl("https://example.com/feed");
feed.setLink("https://example.com");
Mockito.when(httpGetter.get("https://example.com"))
.thenThrow(new RuntimeException("Network error"));
Mockito.when(httpGetter.get("https://example.com")).thenThrow(new RuntimeException("Network error"));
Assertions.assertNull(faviconFetcher.fetch(feed));
}
@@ -122,8 +114,7 @@ class HtmlFaviconFetcherTest {
String html =
"<html><head><link rel=\"icon\" href=\"https://example.com/favicon.png\" /></head><body></body></html>";
HttpResult pageResult =
new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
Mockito.when(httpGetter.get("https://example.com/favicon.png"))
.thenThrow(new RuntimeException("Network error"));

View File

@@ -36,8 +36,7 @@ class RootFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/x-icon";
HttpResult httpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://www.example.com/favicon.ico")).thenReturn(httpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -55,10 +54,8 @@ class RootFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/x-icon";
HttpResult httpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://www.example.com:8000/favicon.ico"))
.thenReturn(httpResult);
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://www.example.com:8000/favicon.ico")).thenReturn(httpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -74,8 +71,7 @@ class RootFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/x-icon";
HttpResult httpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/favicon.ico")).thenReturn(httpResult);
Favicon result = faviconFetcher.fetch(feed);

View File

@@ -71,8 +71,7 @@ class YoutubeFaviconFetcherTest {
{"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}\
"""
.getBytes();
HttpResult apiHttpResult =
new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
HttpResult apiHttpResult = new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
Mockito.when(
httpGetter.get(
"https://www.googleapis.com/youtube/v3/channels?part=snippet&key=test-api-key&forUsername=testUser"))
@@ -83,8 +82,7 @@ class YoutubeFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/png";
HttpResult iconHttpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult iconHttpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenReturn(iconHttpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -106,8 +104,7 @@ class YoutubeFaviconFetcherTest {
{"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}\
"""
.getBytes();
HttpResult apiHttpResult =
new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
HttpResult apiHttpResult = new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
Mockito.when(
httpGetter.get(
"https://www.googleapis.com/youtube/v3/channels?part=snippet&key=test-api-key&id=testChannelId"))
@@ -118,8 +115,7 @@ class YoutubeFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/png";
HttpResult iconHttpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult iconHttpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenReturn(iconHttpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -142,8 +138,7 @@ class YoutubeFaviconFetcherTest {
"""
.getBytes();
HttpResult playlistHttpResult =
new HttpResult(
playlistResponse, "application/json", null, null, null, Duration.ZERO);
new HttpResult(playlistResponse, "application/json", null, null, null, Duration.ZERO);
Mockito.when(
httpGetter.get(
"https://www.googleapis.com/youtube/v3/playlists?part=snippet&key=test-api-key&id=testPlaylistId"))
@@ -158,8 +153,7 @@ class YoutubeFaviconFetcherTest {
"""
.getBytes();
HttpResult channelHttpResult =
new HttpResult(
channelResponse, "application/json", null, null, null, Duration.ZERO);
new HttpResult(channelResponse, "application/json", null, null, null, Duration.ZERO);
Mockito.when(
httpGetter.get(
"https://www.googleapis.com/youtube/v3/channels?part=snippet&key=test-api-key&id=testChannelId"))
@@ -170,8 +164,7 @@ class YoutubeFaviconFetcherTest {
byte[] iconBytes = new byte[1000];
String contentType = "image/png";
HttpResult iconHttpResult =
new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
HttpResult iconHttpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenReturn(iconHttpResult);
Favicon result = faviconFetcher.fetch(feed);
@@ -204,8 +197,7 @@ class YoutubeFaviconFetcherTest {
Mockito.when(config.googleAuthKey()).thenReturn(Optional.of("test-api-key"));
byte[] apiResponse = "{}".getBytes();
HttpResult apiHttpResult =
new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
HttpResult apiHttpResult = new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
Mockito.when(
httpGetter.get(
"https://www.googleapis.com/youtube/v3/channels?part=snippet&key=test-api-key&forUsername=testUser"))

View File

@@ -44,18 +44,14 @@ class FeedFetcherTest {
byte[] html = "html".getBytes();
Mockito.when(getter.get(HttpGetter.HttpRequest.builder(htmlUrl).build()))
.thenReturn(new HttpResult(html, "text/html", null, null, htmlUrl, Duration.ZERO));
Mockito.when(parser.parse(htmlUrl, html))
.thenThrow(new FeedParsingException("invalid feed"));
Mockito.when(parser.parse(htmlUrl, html)).thenThrow(new FeedParsingException("invalid feed"));
String feedUrl = "https://bbb.com/feed";
byte[] feed = "feed".getBytes();
Mockito.when(getter.get(HttpGetter.HttpRequest.builder(feedUrl).build()))
.thenReturn(
new HttpResult(
feed, "application/atom+xml", null, null, feedUrl, Duration.ZERO));
.thenReturn(new HttpResult(feed, "application/atom+xml", null, null, feedUrl, Duration.ZERO));
Mockito.when(parser.parse(feedUrl, feed))
.thenReturn(
new FeedParserResult("title", "link", "iconUrl", null, null, null, null));
.thenReturn(new FeedParserResult("title", "link", "iconUrl", null, null, null, null));
Mockito.when(urlProvider.get(htmlUrl, new String(html))).thenReturn(List.of(feedUrl));
@@ -71,32 +67,13 @@ class FeedFetcherTest {
byte[] content = "content".getBytes();
String lastContentHash = Digests.sha1Hex(content);
Mockito.when(
getter.get(
HttpGetter.HttpRequest.builder(url)
.lastModified(lastModified)
.eTag(etag)
.build()))
.thenReturn(
new HttpResult(
content,
"content-type",
"last-modified-2",
"etag-2",
null,
Duration.ZERO));
Mockito.when(getter.get(HttpGetter.HttpRequest.builder(url).lastModified(lastModified).eTag(etag).build()))
.thenReturn(new HttpResult(content, "content-type", "last-modified-2", "etag-2", null, Duration.ZERO));
NotModifiedException e =
Assertions.assertThrows(
NotModifiedException.class,
() ->
fetcher.fetch(
url,
false,
lastModified,
etag,
Instant.now(),
lastContentHash));
() -> fetcher.fetch(url, false, lastModified, etag, Instant.now(), lastContentHash));
Assertions.assertEquals("last-modified-2", e.getNewLastModifiedHeader());
Assertions.assertEquals("etag-2", e.getNewEtagHeader());

View File

@@ -36,8 +36,7 @@ class FeedRefreshIntervalCalculatorTest {
@BeforeEach
void setUp() {
Mockito.when(instantSource.instant()).thenReturn(NOW);
Mockito.when(config.feedRefresh())
.thenReturn(Mockito.mock(CommaFeedConfiguration.FeedRefresh.class));
Mockito.when(config.feedRefresh()).thenReturn(Mockito.mock(CommaFeedConfiguration.FeedRefresh.class));
Mockito.when(config.feedRefresh().interval()).thenReturn(DEFAULT_INTERVAL);
Mockito.when(config.feedRefresh().maxInterval()).thenReturn(MAX_INTERVAL);
Mockito.when(config.feedRefresh().errors()).thenReturn(errorHandling);
@@ -55,24 +54,20 @@ class FeedRefreshIntervalCalculatorTest {
void withoutValidFor(long averageEntryInterval) {
// averageEntryInterval is ignored when empirical is disabled
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)), averageEntryInterval, Duration.ZERO);
calculator.onFetchSuccess(NOW.minus(Duration.ofDays(5)), averageEntryInterval, Duration.ZERO);
Assertions.assertEquals(NOW.plus(DEFAULT_INTERVAL), result);
}
@Test
void withValidForGreaterThanMaxInterval() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)), 1L, MAX_INTERVAL.plusDays(1));
Instant result = calculator.onFetchSuccess(NOW.minus(Duration.ofDays(5)), 1L, MAX_INTERVAL.plusDays(1));
Assertions.assertEquals(NOW.plus(MAX_INTERVAL), result);
}
@Test
void withValidForLowerThanMaxInterval() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)), 1L, MAX_INTERVAL.minusSeconds(1));
calculator.onFetchSuccess(NOW.minus(Duration.ofDays(5)), 1L, MAX_INTERVAL.minusSeconds(1));
Assertions.assertEquals(NOW.plus(MAX_INTERVAL).minusSeconds(1), result);
}
}
@@ -93,24 +88,19 @@ class FeedRefreshIntervalCalculatorTest {
@Test
void with31DaysOldPublishedDate() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(31)), 1L, Duration.ZERO);
Instant result = calculator.onFetchSuccess(NOW.minus(Duration.ofDays(31)), 1L, Duration.ZERO);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL), result);
}
@Test
void with15DaysOldPublishedDate() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(15)), 1L, Duration.ZERO);
Instant result = calculator.onFetchSuccess(NOW.minus(Duration.ofDays(15)), 1L, Duration.ZERO);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL.dividedBy(2)), result);
}
@Test
void with8DaysOldPublishedDate() {
Instant result =
calculator.onFetchSuccess(NOW.minus(Duration.ofDays(8)), 1L, Duration.ZERO);
Instant result = calculator.onFetchSuccess(NOW.minus(Duration.ofDays(8)), 1L, Duration.ZERO);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL.dividedBy(4)), result);
}
@@ -120,33 +110,26 @@ class FeedRefreshIntervalCalculatorTest {
void averageBetweenBounds() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)),
Duration.ofHours(4).toMillis(),
Duration.ZERO);
NOW.minus(Duration.ofDays(5)), Duration.ofHours(4).toMillis(), Duration.ZERO);
Assertions.assertEquals(NOW.plus(Duration.ofHours(2)), result);
}
@Test
void averageBelowMinimum() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)), 10L, Duration.ZERO);
Instant result = calculator.onFetchSuccess(NOW.minus(Duration.ofDays(5)), 10L, Duration.ZERO);
Assertions.assertEquals(NOW.plus(DEFAULT_INTERVAL), result);
}
@Test
void averageAboveMaximum() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)), Long.MAX_VALUE, Duration.ZERO);
calculator.onFetchSuccess(NOW.minus(Duration.ofDays(5)), Long.MAX_VALUE, Duration.ZERO);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL.dividedBy(4)), result);
}
@Test
void noAverage() {
Instant result =
calculator.onFetchSuccess(
NOW.minus(Duration.ofDays(5)), null, Duration.ZERO);
Instant result = calculator.onFetchSuccess(NOW.minus(Duration.ofDays(5)), null, Duration.ZERO);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL), result);
}
}
@@ -162,9 +145,7 @@ class FeedRefreshIntervalCalculatorTest {
@ValueSource(longs = {0, 1, 300, 86400000L})
void withoutValidFor(long averageEntryInterval) {
// averageEntryInterval is ignored when empirical is disabled
Instant result =
calculator.onFeedNotModified(
NOW.minus(Duration.ofDays(5)), averageEntryInterval);
Instant result = calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), averageEntryInterval);
Assertions.assertEquals(NOW.plus(DEFAULT_INTERVAL), result);
}
}
@@ -206,30 +187,25 @@ class FeedRefreshIntervalCalculatorTest {
@Test
void averageBetweenBounds() {
Instant result =
calculator.onFeedNotModified(
NOW.minus(Duration.ofDays(5)), Duration.ofHours(4).toMillis());
calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), Duration.ofHours(4).toMillis());
Assertions.assertEquals(NOW.plus(Duration.ofHours(2)), result);
}
@Test
void averageBelowMinimum() {
Instant result =
calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), 10L);
Instant result = calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), 10L);
Assertions.assertEquals(NOW.plus(DEFAULT_INTERVAL), result);
}
@Test
void averageAboveMaximum() {
Instant result =
calculator.onFeedNotModified(
NOW.minus(Duration.ofDays(5)), Long.MAX_VALUE);
Instant result = calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), Long.MAX_VALUE);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL.dividedBy(4)), result);
}
@Test
void noAverage() {
Instant result =
calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), null);
Instant result = calculator.onFeedNotModified(NOW.minus(Duration.ofDays(5)), null);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL), result);
}
}
@@ -251,8 +227,7 @@ class FeedRefreshIntervalCalculatorTest {
@Test
void highErrorCount() {
Mockito.when(config.feedRefresh().errors().backoffInterval())
.thenReturn(Duration.ofHours(1));
Mockito.when(config.feedRefresh().errors().backoffInterval()).thenReturn(Duration.ofHours(1));
Instant result = calculator.onFetchError(5);
Assertions.assertEquals(NOW.plus(Duration.ofHours(3)), result);
@@ -260,8 +235,7 @@ class FeedRefreshIntervalCalculatorTest {
@Test
void veryHighErrorCount() {
Mockito.when(config.feedRefresh().errors().backoffInterval())
.thenReturn(Duration.ofHours(1));
Mockito.when(config.feedRefresh().errors().backoffInterval()).thenReturn(Duration.ofHours(1));
Instant result = calculator.onFetchError(100000);
Assertions.assertEquals(NOW.plus(MAX_INTERVAL), result);

View File

@@ -31,11 +31,9 @@ class FeedUtilsTest {
Assertions.assertEquals("Test Entry", syndEntry.getTitle());
Assertions.assertEquals("Author Name", syndEntry.getAuthor());
Assertions.assertEquals(1, syndEntry.getContents().size());
Assertions.assertEquals(
"This is a test entry content.", syndEntry.getContents().getFirst().getValue());
Assertions.assertEquals("This is a test entry content.", syndEntry.getContents().getFirst().getValue());
Assertions.assertEquals(1, syndEntry.getEnclosures().size());
Assertions.assertEquals(
"http://example.com/enclosure.mp3", syndEntry.getEnclosures().getFirst().getUrl());
Assertions.assertEquals("http://example.com/enclosure.mp3", syndEntry.getEnclosures().getFirst().getUrl());
Assertions.assertEquals("audio/mpeg", syndEntry.getEnclosures().getFirst().getType());
Assertions.assertEquals("http://example.com/test-entry", syndEntry.getLink());
Assertions.assertEquals(Date.from(Instant.ofEpochSecond(1)), syndEntry.getPublishedDate());

View File

@@ -12,13 +12,10 @@ class EncodingDetectorTest {
Assertions.assertNull(encodingDetector.extractDeclaredEncoding("<?xml ?>".getBytes()));
Assertions.assertNull(encodingDetector.extractDeclaredEncoding("<feed></feed>".getBytes()));
Assertions.assertEquals(
"UTF-8",
encodingDetector.extractDeclaredEncoding("<?xml encoding=\"UTF-8\" ?>".getBytes()));
"UTF-8", encodingDetector.extractDeclaredEncoding("<?xml encoding=\"UTF-8\" ?>".getBytes()));
Assertions.assertEquals(
"UTF-8",
encodingDetector.extractDeclaredEncoding("<?xml encoding='UTF-8' ?>".getBytes()));
"UTF-8", encodingDetector.extractDeclaredEncoding("<?xml encoding='UTF-8' ?>".getBytes()));
Assertions.assertEquals(
"UTF-8",
encodingDetector.extractDeclaredEncoding("<?xml encoding='UTF-8'?>".getBytes()));
"UTF-8", encodingDetector.extractDeclaredEncoding("<?xml encoding='UTF-8'?>".getBytes()));
}
}

View File

@@ -7,38 +7,25 @@ class TextDirectionDetectorTest {
@Test
void testEstimateDirection() {
Assertions.assertEquals(TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect(""));
Assertions.assertEquals(TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect(" "));
Assertions.assertEquals(TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect("! (...)"));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect(""));
TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect("Pure Ascii content"));
Assertions.assertEquals(TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect("-17.0%"));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect(" "));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT,
TextDirectionDetector.detect("! (...)"));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT,
TextDirectionDetector.detect("Pure Ascii content"));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT,
TextDirectionDetector.detect("-17.0%"));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT,
TextDirectionDetector.detect("http://foo/bar/"));
TextDirectionDetector.Direction.LEFT_TO_RIGHT, TextDirectionDetector.detect("http://foo/bar/"));
Assertions.assertEquals(
TextDirectionDetector.Direction.LEFT_TO_RIGHT,
TextDirectionDetector.detect(
"http://foo/bar/?s=\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0"
+ "\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0"
+ "\u05d0\u05d0\u05d0\u05d0\u05d0\u05d0"));
Assertions.assertEquals(TextDirectionDetector.Direction.RIGHT_TO_LEFT, TextDirectionDetector.detect("\u05d0"));
Assertions.assertEquals(TextDirectionDetector.Direction.RIGHT_TO_LEFT, TextDirectionDetector.detect("\u05d0"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect("\u05d0"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect("\u05d0"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect(
"http://foo/bar/ \u05d0 http://foo2/bar2/ http://foo3/bar3/"));
TextDirectionDetector.detect("http://foo/bar/ \u05d0 http://foo2/bar2/ http://foo3/bar3/"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect(
@@ -69,8 +56,7 @@ class TextDirectionDetectorTest {
+ "\u05d9 \u05d1\u05d0\u05ea\u05e8"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect(
"CAPTCHA \u05de\u05e9\u05d5\u05db\u05dc\u05dc " + "\u05de\u05d3\u05d9?"));
TextDirectionDetector.detect("CAPTCHA \u05de\u05e9\u05d5\u05db\u05dc\u05dc " + "\u05de\u05d3\u05d9?"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect(
@@ -86,12 +72,10 @@ class TextDirectionDetectorTest {
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect(
"5710 5720 5730. \u05d4\u05d3\u05dc\u05ea. "
+ "\u05d4\u05e0\u05e9\u05d9\u05e7\u05d4"));
"5710 5720 5730. \u05d4\u05d3\u05dc\u05ea. " + "\u05d4\u05e0\u05e9\u05d9\u05e7\u05d4"));
Assertions.assertEquals(
TextDirectionDetector.Direction.RIGHT_TO_LEFT,
TextDirectionDetector.detect(
"\u05d4\u05d3\u05dc\u05ea http://www.google.com "
+ "http://www.gmail.com"));
"\u05d4\u05d3\u05dc\u05ea http://www.google.com " + "http://www.gmail.com"));
}
}

View File

@@ -13,22 +13,19 @@ class XMLCleanerTest {
@Test
void removesWhitespaceBeforeXmlTag() {
String xml = " \n\t<feed>content</feed>";
Assertions.assertEquals(
"<feed>content</feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
Assertions.assertEquals("<feed>content</feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
}
@Test
void removesTextBeforeXmlTag() {
String xml = "some text here<feed>content</feed>";
Assertions.assertEquals(
"<feed>content</feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
Assertions.assertEquals("<feed>content</feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
}
@Test
void returnsUnchangedWhenStartsWithXmlTag() {
String xml = "<feed>content</feed>";
Assertions.assertEquals(
"<feed>content</feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
Assertions.assertEquals("<feed>content</feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
}
@Test
@@ -56,8 +53,7 @@ class XMLCleanerTest {
void preservesMultipleXmlTags() {
String xml = "garbage<feed><item>content</item></feed>";
Assertions.assertEquals(
"<feed><item>content</item></feed>",
xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
"<feed><item>content</item></feed>", xmlCleaner.removeCharactersBeforeFirstXmlTag(xml));
}
}
@@ -66,38 +62,32 @@ class XMLCleanerTest {
@Test
void removesNullCharacter() {
String xml = "<feed>content\u0000here</feed>";
Assertions.assertEquals(
"<feed>contenthere</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
Assertions.assertEquals("<feed>contenthere</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
}
@Test
void removesInvalidControlCharacters() {
String xml = "<feed>content\u0001\u0002\u0003here</feed>";
Assertions.assertEquals(
"<feed>contenthere</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
Assertions.assertEquals("<feed>contenthere</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
}
@Test
void preservesValidXmlCharacters() {
String xml = "<feed>content with\ttab\nand newline</feed>";
Assertions.assertEquals(
"<feed>content with\ttab\nand newline</feed>",
xmlCleaner.removeInvalidXmlCharacters(xml));
"<feed>content with\ttab\nand newline</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
}
@Test
void preservesUnicodeCharacters() {
String xml = "<feed>café résumé 中文 العربية</feed>";
Assertions.assertEquals(
"<feed>café résumé 中文 العربية</feed>",
xmlCleaner.removeInvalidXmlCharacters(xml));
Assertions.assertEquals("<feed>café résumé 中文 العربية</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
}
@Test
void preservesEmojiCharacters() {
String xml = "<feed>🎮💪✅</feed>";
Assertions.assertEquals(
"<feed>🎮💪✅</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
Assertions.assertEquals("<feed>🎮💪✅</feed>", xmlCleaner.removeInvalidXmlCharacters(xml));
}
@Test
@@ -141,31 +131,26 @@ class XMLCleanerTest {
@Test
void replacesMultipleOccurrencesOfSameEntity() {
String source = "&nbsp;&nbsp;&nbsp;";
Assertions.assertEquals(
"&#160;&#160;&#160;",
xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
Assertions.assertEquals("&#160;&#160;&#160;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
}
@Test
void preservesTextWithoutEntities() {
String source = "<feed>regular content</feed>";
Assertions.assertEquals(
"<feed>regular content</feed>",
xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
"<feed>regular content</feed>", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
}
@Test
void preservesNumericEntities() {
String source = "&#180;&#8242;";
Assertions.assertEquals(
"&#180;&#8242;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
Assertions.assertEquals("&#180;&#8242;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
}
@Test
void replacesCommonHtmlEntities() {
String source = "&amp;&quot;";
Assertions.assertEquals(
"&#38;&#34;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
Assertions.assertEquals("&#38;&#34;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
}
@Test
@@ -193,15 +178,13 @@ class XMLCleanerTest {
@Test
void handlesEntityAtStartOfString() {
String source = "&amp;test";
Assertions.assertEquals(
"&#38;test", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
Assertions.assertEquals("&#38;test", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
}
@Test
void handlesEntityAtEndOfString() {
String source = "test&amp;";
Assertions.assertEquals(
"test&#38;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
Assertions.assertEquals("test&#38;", xmlCleaner.replaceHtmlEntitiesWithNumericEntities(source));
}
@Test
@@ -218,8 +201,7 @@ class XMLCleanerTest {
void testRemoveDoctype() {
String source = "<!DOCTYPE html><html><head></head><body></body></html>";
Assertions.assertEquals(
"<html><head></head><body></body></html>",
xmlCleaner.removeDoctypeDeclarations(source));
"<html><head></head><body></body></html>", xmlCleaner.removeDoctypeDeclarations(source));
}
@Test
@@ -241,10 +223,8 @@ class XMLCleanerTest {
@Test
void removesComplexDoctypeWithSystemId() {
String source =
"<!DOCTYPE html SYSTEM \"about:legacy-compat\"><html><body></body></html>";
Assertions.assertEquals(
"<html><body></body></html>", xmlCleaner.removeDoctypeDeclarations(source));
String source = "<!DOCTYPE html SYSTEM \"about:legacy-compat\"><html><body></body></html>";
Assertions.assertEquals("<html><body></body></html>", xmlCleaner.removeDoctypeDeclarations(source));
}
@Test
@@ -276,8 +256,7 @@ class XMLCleanerTest {
void preservesContentWithoutDoctype() {
String source = "<html><body>No doctype here</body></html>";
Assertions.assertEquals(
"<html><body>No doctype here</body></html>",
xmlCleaner.removeDoctypeDeclarations(source));
"<html><body>No doctype here</body></html>", xmlCleaner.removeDoctypeDeclarations(source));
}
@Test

View File

@@ -111,9 +111,7 @@ class OPMLExporterTest {
private boolean containsFeed(List<Outline> outlines, String title, String url) {
for (Outline o : outlines) {
if ("rss".equals(o.getType())
&& title.equals(o.getTitle())
&& o.getAttributeValue("xmlUrl").equals(url)) {
if ("rss".equals(o.getType()) && title.equals(o.getTitle()) && o.getAttributeValue("xmlUrl").equals(url)) {
return true;
}
}

View File

@@ -36,21 +36,16 @@ class OPMLImporterTest {
testOpmlVersion("/opml/opml_noversion.xml");
}
private void testOpmlVersion(String fileName)
throws IOException, IllegalArgumentException, FeedException {
private void testOpmlVersion(String fileName) throws IOException, IllegalArgumentException, FeedException {
XMLCleaner xmlCleaner = Mockito.mock(XMLCleaner.class);
FeedCategoryDAO feedCategoryDAO = Mockito.mock(FeedCategoryDAO.class);
FeedSubscriptionService feedSubscriptionService =
Mockito.mock(FeedSubscriptionService.class);
FeedSubscriptionService feedSubscriptionService = Mockito.mock(FeedSubscriptionService.class);
User user = Mockito.mock(User.class);
Mockito.when(xmlCleaner.clean(Mockito.anyString()))
.thenAnswer(invocation -> invocation.getArgument(0));
String xml =
IOUtils.toString(getClass().getResourceAsStream(fileName), StandardCharsets.UTF_8);
Mockito.when(xmlCleaner.clean(Mockito.anyString())).thenAnswer(invocation -> invocation.getArgument(0));
String xml = IOUtils.toString(getClass().getResourceAsStream(fileName), StandardCharsets.UTF_8);
OPMLImporter importer =
new OPMLImporter(xmlCleaner, feedCategoryDAO, feedSubscriptionService);
OPMLImporter importer = new OPMLImporter(xmlCleaner, feedCategoryDAO, feedSubscriptionService);
importer.importOpml(user, xml);
Mockito.verify(feedSubscriptionService)

View File

@@ -23,8 +23,7 @@ class FeedEntryFilteringServiceTest {
@BeforeEach
void init() {
config = Mockito.mock(CommaFeedConfiguration.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(config.feedRefresh().filteringExpressionEvaluationTimeout())
.thenReturn(Duration.ofSeconds(30));
Mockito.when(config.feedRefresh().filteringExpressionEvaluationTimeout()).thenReturn(Duration.ofSeconds(30));
service = new FeedEntryFilteringService(config);
@@ -75,16 +74,12 @@ class FeedEntryFilteringServiceTest {
@Test
void andExpression() throws FeedEntryFilterException {
Assertions.assertTrue(
service.filterMatchesEntry(
"author == \"Athou\" && url.contains(\"github\")", entry));
Assertions.assertTrue(service.filterMatchesEntry("author == \"Athou\" && url.contains(\"github\")", entry));
}
@Test
void orExpression() throws FeedEntryFilterException {
Assertions.assertTrue(
service.filterMatchesEntry(
"author == \"other\" || url.contains(\"github\")", entry));
Assertions.assertTrue(service.filterMatchesEntry("author == \"other\" || url.contains(\"github\")", entry));
}
@Test
@@ -95,8 +90,7 @@ class FeedEntryFilteringServiceTest {
@Test
void incorrectExpressionThrowsException() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("not valid cel", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("not valid cel", entry));
}
@Test
@@ -124,8 +118,7 @@ class FeedEntryFilteringServiceTest {
FeedEntryContent content = entry.getContent();
content.setCategories("tech, programming, java");
entry.setContent(content);
Assertions.assertTrue(
service.filterMatchesEntry("categories.contains(\"programming\")", entry));
Assertions.assertTrue(service.filterMatchesEntry("categories.contains(\"programming\")", entry));
}
@Test
@@ -145,8 +138,7 @@ class FeedEntryFilteringServiceTest {
@Test
void caseInsensitiveContentMatchUsingLowerVariable() throws FeedEntryFilterException {
Assertions.assertTrue(
service.filterMatchesEntry("contentLower.contains(\"merge\")", entry));
Assertions.assertTrue(service.filterMatchesEntry("contentLower.contains(\"merge\")", entry));
}
@Test
@@ -154,8 +146,7 @@ class FeedEntryFilteringServiceTest {
FeedEntryContent content = entry.getContent();
content.setCategories("Tech, Programming, Java");
entry.setContent(content);
Assertions.assertTrue(
service.filterMatchesEntry("categoriesLower.contains(\"tech\")", entry));
Assertions.assertTrue(service.filterMatchesEntry("categoriesLower.contains(\"tech\")", entry));
}
@Nested
@@ -165,36 +156,28 @@ class FeedEntryFilteringServiceTest {
void sandboxBlocksSystemPropertyAccess() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"java.lang.System.getProperty(\"user.home\")", entry));
() -> service.filterMatchesEntry("java.lang.System.getProperty(\"user.home\")", entry));
}
@Test
void sandboxBlocksRuntimeExec() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"java.lang.Runtime.getRuntime().exec(\"calc\")", entry));
() -> service.filterMatchesEntry("java.lang.Runtime.getRuntime().exec(\"calc\")", entry));
}
@Test
void sandboxBlocksProcessBuilder() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"new java.lang.ProcessBuilder(\"cmd\").start()", entry));
() -> service.filterMatchesEntry("new java.lang.ProcessBuilder(\"cmd\").start()", entry));
}
@Test
void sandboxBlocksClassLoading() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"java.lang.Class.forName(\"java.lang.Runtime\")", entry));
() -> service.filterMatchesEntry("java.lang.Class.forName(\"java.lang.Runtime\")", entry));
}
@Test
@@ -208,9 +191,7 @@ class FeedEntryFilteringServiceTest {
void sandboxBlocksFileAccess() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"new java.io.File(\"/etc/passwd\").exists()", entry));
() -> service.filterMatchesEntry("new java.io.File(\"/etc/passwd\").exists()", entry));
}
@Test
@@ -219,18 +200,14 @@ class FeedEntryFilteringServiceTest {
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"java.nio.file.Files.readString(java.nio.file.Paths.get(\"/etc/passwd\"))",
entry));
"java.nio.file.Files.readString(java.nio.file.Paths.get(\"/etc/passwd\"))", entry));
}
@Test
void sandboxBlocksNetworkAccess() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() ->
service.filterMatchesEntry(
"new java.net.URL(\"http://evil.com\").openConnection()",
entry));
() -> service.filterMatchesEntry("new java.net.URL(\"http://evil.com\").openConnection()", entry));
}
@Test
@@ -274,50 +251,42 @@ class FeedEntryFilteringServiceTest {
@Test
void sandboxBlocksMethodInvocationOnStrings() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("title.toCharArray()", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("title.toCharArray()", entry));
}
@Test
void sandboxBlocksArbitraryJavaMethodCalls() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("title.getBytes()", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("title.getBytes()", entry));
}
@Test
void sandboxOnlyAllowsDeclaredVariables() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("System", entry));
Assertions.assertThrows(FeedEntryFilterException.class, () -> service.filterMatchesEntry("System", entry));
}
@Test
void sandboxBlocksConstructorCalls() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("new String(\"test\")", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("new String(\"test\")", entry));
}
@Test
void sandboxBlocksStaticMethodCalls() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("String.valueOf(123)", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("String.valueOf(123)", entry));
}
@Test
void sandboxBlocksLambdaExpressions() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("() -> true", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("() -> true", entry));
}
@Test
void sandboxBlocksObjectInstantiation() {
Assertions.assertThrows(
FeedEntryFilterException.class,
() -> service.filterMatchesEntry("java.util.HashMap{}", entry));
FeedEntryFilterException.class, () -> service.filterMatchesEntry("java.util.HashMap{}", entry));
}
}
}

View File

@@ -17,9 +17,7 @@ class PasswordEncryptionServiceTest {
// make sure the encrypted password is always the same for a fixed salt
Assertions.assertEquals(
"8b4660158141d9f4f7865718b9a2b940a3e3cea9",
HexFormat.of().formatHex(encryptedPassword));
Assertions.assertTrue(
passwordEncryptionService.authenticate(password, encryptedPassword, salt));
"8b4660158141d9f4f7865718b9a2b940a3e3cea9", HexFormat.of().formatHex(encryptedPassword));
Assertions.assertTrue(passwordEncryptionService.authenticate(password, encryptedPassword, salt));
}
}

View File

@@ -48,11 +48,9 @@ class PushNotificationServiceTest {
HttpClientFactory httpClientFactory =
new HttpClientFactory(config, Mockito.mock(com.commafeed.CommaFeedVersion.class));
MetricRegistry metricRegistry = Mockito.mock(MetricRegistry.class);
Mockito.when(metricRegistry.meter(Mockito.anyString()))
.thenReturn(Mockito.mock(Meter.class));
Mockito.when(metricRegistry.meter(Mockito.anyString())).thenReturn(Mockito.mock(Meter.class));
this.pushNotificationService =
new PushNotificationService(httpClientFactory, metricRegistry, config);
this.pushNotificationService = new PushNotificationService(httpClientFactory, metricRegistry, config);
this.userSettings = new PushNotificationUserSettings();
@@ -78,8 +76,7 @@ class PushNotificationServiceTest {
.withBody("Test Entry"))
.respond(HttpResponse.response().withStatusCode(200));
Assertions.assertDoesNotThrow(
() -> pushNotificationService.notify(userSettings, subscription, entry));
Assertions.assertDoesNotThrow(() -> pushNotificationService.notify(userSettings, subscription, entry));
}
@Test
@@ -113,8 +110,7 @@ class PushNotificationServiceTest {
""")))
.respond(HttpResponse.response().withStatusCode(200));
Assertions.assertDoesNotThrow(
() -> pushNotificationService.notify(userSettings, subscription, entry));
Assertions.assertDoesNotThrow(() -> pushNotificationService.notify(userSettings, subscription, entry));
}
@Test
@@ -124,8 +120,7 @@ class PushNotificationServiceTest {
userSettings.setServerUrl("http://localhost:" + mockServerClient.getPort());
userSettings.setTopic("test-topic");
Assertions.assertDoesNotThrow(
() -> pushNotificationService.notify(userSettings, subscription, entry));
Assertions.assertDoesNotThrow(() -> pushNotificationService.notify(userSettings, subscription, entry));
mockServerClient.verifyZeroInteractions();
}

View File

@@ -108,15 +108,12 @@ class UserServiceTest {
Mockito.when(userDAO.findByName("test")).thenReturn(normalUser);
Mockito.when(
passwordEncryptionService.authenticate(
Mockito.anyString(),
Mockito.any(byte[].class),
Mockito.any(byte[].class)))
Mockito.anyString(), Mockito.any(byte[].class), Mockito.any(byte[].class)))
.thenReturn(false);
userService.login("test", "password");
Mockito.verify(passwordEncryptionService)
.authenticate("password", ENCRYPTED_PASSWORD, SALT);
Mockito.verify(passwordEncryptionService).authenticate("password", ENCRYPTED_PASSWORD, SALT);
}
@Test
@@ -124,9 +121,7 @@ class UserServiceTest {
Mockito.when(userDAO.findByName("test")).thenReturn(normalUser);
Mockito.when(
passwordEncryptionService.authenticate(
Mockito.anyString(),
Mockito.any(byte[].class),
Mockito.any(byte[].class)))
Mockito.anyString(), Mockito.any(byte[].class), Mockito.any(byte[].class)))
.thenReturn(false);
Optional<User> authenticatedUser = userService.login("test", "password");
@@ -139,9 +134,7 @@ class UserServiceTest {
Mockito.when(userDAO.findByName("test")).thenReturn(normalUser);
Mockito.when(
passwordEncryptionService.authenticate(
Mockito.anyString(),
Mockito.any(byte[].class),
Mockito.any(byte[].class)))
Mockito.anyString(), Mockito.any(byte[].class), Mockito.any(byte[].class)))
.thenReturn(true);
Mockito.doNothing().when(postLoginActivities).executeFor(Mockito.any(User.class));
@@ -155,9 +148,7 @@ class UserServiceTest {
Mockito.when(userDAO.findByName("test")).thenReturn(normalUser);
Mockito.when(
passwordEncryptionService.authenticate(
Mockito.anyString(),
Mockito.any(byte[].class),
Mockito.any(byte[].class)))
Mockito.anyString(), Mockito.any(byte[].class), Mockito.any(byte[].class)))
.thenReturn(true);
Mockito.doNothing().when(postLoginActivities).executeFor(Mockito.any(User.class));

View File

@@ -64,13 +64,7 @@ class DatabaseCleaningServiceTest {
service =
new DatabaseCleaningService(
config,
unitOfWork,
feedDAO,
feedEntryDAO,
feedEntryContentDAO,
feedEntryStatusDAO,
metrics);
config, unitOfWork, feedDAO, feedEntryDAO, feedEntryContentDAO, feedEntryStatusDAO, metrics);
}
@Test
@@ -97,13 +91,11 @@ class DatabaseCleaningServiceTest {
@Test
void cleanContentsWithoutEntriesDeletesContents() {
Mockito.when(feedEntryContentDAO.deleteWithoutEntries(Mockito.anyInt()))
.thenReturn(50L, 30L, 0L);
Mockito.when(feedEntryContentDAO.deleteWithoutEntries(Mockito.anyInt())).thenReturn(50L, 30L, 0L);
service.cleanContentsWithoutEntries();
Mockito.verify(feedEntryContentDAO, Mockito.times(3))
.deleteWithoutEntries(Mockito.anyInt());
Mockito.verify(feedEntryContentDAO, Mockito.times(3)).deleteWithoutEntries(Mockito.anyInt());
}
@Test
@@ -133,13 +125,11 @@ class DatabaseCleaningServiceTest {
void cleanEntriesOlderThanDeletesOldEntries() {
Instant cutoff = LocalDate.now().minusDays(30).atStartOfDay().toInstant(ZoneOffset.UTC);
Mockito.when(feedEntryDAO.deleteEntriesOlderThan(cutoff, BATCH_SIZE, false))
.thenReturn(100, 50, 0);
Mockito.when(feedEntryDAO.deleteEntriesOlderThan(cutoff, BATCH_SIZE, false)).thenReturn(100, 50, 0);
service.cleanEntriesOlderThan(cutoff);
Mockito.verify(feedEntryDAO, Mockito.times(3))
.deleteEntriesOlderThan(cutoff, BATCH_SIZE, false);
Mockito.verify(feedEntryDAO, Mockito.times(3)).deleteEntriesOlderThan(cutoff, BATCH_SIZE, false);
Mockito.verify(entriesDeletedMeter, Mockito.times(3)).mark(Mockito.anyLong());
}
@@ -147,8 +137,7 @@ class DatabaseCleaningServiceTest {
void cleanStatusesOlderThanDeletesOldStatuses() {
Instant cutoff = LocalDate.now().minusDays(60).atStartOfDay().toInstant(ZoneOffset.UTC);
Mockito.when(feedEntryStatusDAO.deleteOldStatuses(cutoff, BATCH_SIZE))
.thenReturn(200L, 100L, 0L);
Mockito.when(feedEntryStatusDAO.deleteOldStatuses(cutoff, BATCH_SIZE)).thenReturn(200L, 100L, 0L);
service.cleanStatusesOlderThan(cutoff);

View File

@@ -25,8 +25,7 @@ class InPageReferenceFeedURLProviderTest {
""";
Assertions.assertIterableEquals(
List.of("http://example.com/feed.atom", "http://example.com/feed.rss"),
provider.get(url, html));
List.of("http://example.com/feed.atom", "http://example.com/feed.rss"), provider.get(url, html));
}
@Test

View File

@@ -18,8 +18,7 @@ class YoutubeFeedURLProviderTest {
@Test
void doesNotmatchYoutubeChannelURL() {
Assertions.assertTrue(
provider.get("https://www.anothersite.com/channel/abc", null).isEmpty());
Assertions.assertTrue(provider.get("https://www.anothersite.com/channel/abc", null).isEmpty());
Assertions.assertTrue(provider.get("https://www.youtube.com/user/abc", null).isEmpty());
}
}

View File

@@ -35,8 +35,7 @@ class AuthentificationIT {
Page page = context.newPage();
page.navigate(getLoginPageUrl());
PlaywrightTestUtils.login(page, TestConstants.ADMIN_USERNAME, "wrong_password");
PlaywrightAssertions.assertThat(page.getByRole(AriaRole.ALERT))
.containsText("Wrong username or password");
PlaywrightAssertions.assertThat(page.getByRole(AriaRole.ALERT)).containsText("Wrong username or password");
}
@Test

View File

@@ -25,8 +25,7 @@ class InitialSetupIT {
page.getByPlaceholder("Admin User Name").fill(TestConstants.ADMIN_USERNAME);
page.getByPlaceholder("Password").fill(TestConstants.ADMIN_PASSWORD);
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Create Admin Account"))
.click();
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Create Admin Account")).click();
PlaywrightAssertions.assertThat(page).hasURL("http://localhost:8085/#/app/category/all");
}

View File

@@ -46,14 +46,12 @@ class ReadingIT {
HttpResponse.response()
.withBody(
IOUtils.toString(
getClass().getResource("/feed/rss.xml"),
StandardCharsets.UTF_8))
getClass().getResource("/feed/rss.xml"), StandardCharsets.UTF_8))
.withDelay(TimeUnit.MILLISECONDS, 100));
PlaywrightTestUtils.initialSetup();
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -74,18 +72,13 @@ class ReadingIT {
Locator sidebar = page.getByRole(AriaRole.NAVIGATION);
Locator main = page.getByRole(AriaRole.MAIN);
PlaywrightAssertions.assertThat(main.getByText("You don't have any subscriptions yet."))
.hasCount(1);
PlaywrightAssertions.assertThat(main.getByText("You don't have any subscriptions yet.")).hasCount(1);
// subscribe
header.getByRole(AriaRole.BUTTON, new Locator.GetByRoleOptions().setName("Subscribe"))
.click();
header.getByRole(AriaRole.BUTTON, new Locator.GetByRoleOptions().setName("Subscribe")).click();
main.getByText("Feed URL *").fill("http://localhost:" + this.mockServerClient.getPort());
main.getByRole(AriaRole.BUTTON, new Locator.GetByRoleOptions().setName("Next")).click();
main.getByRole(
AriaRole.BUTTON,
new Locator.GetByRoleOptions().setName("Subscribe").setExact(true))
.click();
main.getByRole(AriaRole.BUTTON, new Locator.GetByRoleOptions().setName("Subscribe").setExact(true)).click();
// click on subscription
sidebar.getByText(Pattern.compile("CommaFeed test feed\\d+")).click();

View File

@@ -40,8 +40,7 @@ import java.util.Objects;
@Getter
public abstract class BaseIT {
private static final HttpRequest FEED_REQUEST =
HttpRequest.request().withMethod("GET").withPath("/");
private static final HttpRequest FEED_REQUEST = HttpRequest.request().withMethod("GET").withPath("/");
@Getter private MockServerClient mockServerClient;
private Client client;
@@ -62,14 +61,11 @@ public abstract class BaseIT {
URL resource = Objects.requireNonNull(getClass().getResource("/feed/rss.xml"));
this.mockServerClient
.when(FEED_REQUEST)
.respond(
HttpResponse.response()
.withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
.respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
// remove when Quarkus supports Jackson 3
RestAssured.config =
RestAssured.config()
.objectMapperConfig(new ObjectMapperConfig(ObjectMapperType.JACKSON_2));
RestAssured.config().objectMapperConfig(new ObjectMapperConfig(ObjectMapperType.JACKSON_2));
}
@AfterEach
@@ -89,9 +85,7 @@ public abstract class BaseIT {
URL resource = Objects.requireNonNull(getClass().getResource("/feed/rss_2.xml"));
mockServerClient
.when(FEED_REQUEST)
.respond(
HttpResponse.response()
.withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
.respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
}
protected void initialSetup(String userName, String password) {
@@ -124,9 +118,7 @@ public abstract class BaseIT {
.extract()
.headers()
.getList(HttpHeaders.SET_COOKIE);
return setCookieHeaders.stream()
.flatMap(h -> HttpCookie.parse(h.getValue()).stream())
.toList();
return setCookieHeaders.stream().flatMap(h -> HttpCookie.parse(h.getValue()).stream()).toList();
}
protected String createCategory(String name) {
@@ -223,10 +215,7 @@ public abstract class BaseIT {
protected Entries getCategoryEntries(String categoryId, String keywords) {
return RestAssured.given()
.get(
"rest/category/entries?id={id}&readType=all&keywords={keywords}",
categoryId,
keywords)
.get("rest/category/entries?id={id}&readType=all&keywords={keywords}", categoryId, keywords)
.then()
.statusCode(HttpStatus.SC_OK)
.extract()

View File

@@ -14,11 +14,6 @@ class CompressionIT {
@ParameterizedTest
@ValueSource(strings = {"/rest/server/get", "/"})
void servedWithCompression(String path) {
RestAssured.given()
.when()
.get(path)
.then()
.statusCode(200)
.header(HttpHeaders.CONTENT_ENCODING, "gzip");
RestAssured.given().when().get(path).then().statusCode(200).header(HttpHeaders.CONTENT_ENCODING, "gzip");
}
}

View File

@@ -29,8 +29,7 @@ class PushNotificationIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -41,13 +40,11 @@ class PushNotificationIT extends BaseIT {
@Test
void receivedPushNotifications() throws IOException {
// mock ntfy server
HttpRequest ntfyPost =
HttpRequest.request().withMethod("POST").withPath("/ntfy/integration-test");
HttpRequest ntfyPost = HttpRequest.request().withMethod("POST").withPath("/ntfy/integration-test");
getMockServerClient().when(ntfyPost).respond(HttpResponse.response().withStatusCode(200));
// enable push notifications
Settings settings =
RestAssured.given().get("rest/user/settings").then().extract().as(Settings.class);
Settings settings = RestAssured.given().get("rest/user/settings").then().extract().as(Settings.class);
settings.getPushNotificationSettings().setType(PushNotificationType.NTFY);
settings.getPushNotificationSettings()
.setServerUrl("http://localhost:" + getMockServerClient().getPort() + "/ntfy");
@@ -84,7 +81,6 @@ class PushNotificationIT extends BaseIT {
// await push notification for the two entries in the feed
Awaitility.await()
.atMost(Duration.ofSeconds(20))
.untilAsserted(
() -> getMockServerClient().verify(ntfyPost, VerificationTimes.exactly(2)));
.untilAsserted(() -> getMockServerClient().verify(ntfyPost, VerificationTimes.exactly(2)));
}
}

View File

@@ -57,9 +57,7 @@ class SecurityIT extends BaseIT {
cookies.forEach(c -> Assertions.assertTrue(c.getMaxAge() > 0));
RestAssured.given()
.header(
HttpHeaders.COOKIE,
cookies.stream().map(HttpCookie::toString).collect(Collectors.joining(";")))
.header(HttpHeaders.COOKIE, cookies.stream().map(HttpCookie::toString).collect(Collectors.joining(";")))
.get("rest/user/profile")
.then()
.statusCode(HttpStatus.SC_OK);
@@ -71,11 +69,7 @@ class SecurityIT extends BaseIT {
RestAssured.given()
.auth()
.none()
.formParams(
"j_username",
TestConstants.ADMIN_USERNAME,
"j_password",
"wrong-password")
.formParams("j_username", TestConstants.ADMIN_USERNAME, "j_password", "wrong-password")
.post("j_security_check")
.then()
.statusCode(HttpStatus.SC_UNAUTHORIZED)
@@ -396,9 +390,7 @@ class SecurityIT extends BaseIT {
}
private String session(String userName, String password) {
return login(userName, password).stream()
.map(HttpCookie::toString)
.collect(Collectors.joining(";"));
return login(userName, password).stream().map(HttpCookie::toString).collect(Collectors.joining(";"));
}
private UserModel profile(String session) {
@@ -412,10 +404,6 @@ class SecurityIT extends BaseIT {
}
private void assertSessionStatus(String session, int status) {
RestAssured.given()
.header(HttpHeaders.COOKIE, session)
.get("rest/user/profile")
.then()
.statusCode(status);
RestAssured.given().header(HttpHeaders.COOKIE, session).get("rest/user/profile").then().statusCode(status);
}
}

View File

@@ -12,12 +12,7 @@ class StaticFilesIT {
@ParameterizedTest
@ValueSource(strings = {"/", "/openapi"})
void servedWithoutCache(String path) {
RestAssured.given()
.when()
.get(path)
.then()
.statusCode(200)
.header("Cache-Control", "no-cache");
RestAssured.given().when().get(path).then().statusCode(200).header("Cache-Control", "no-cache");
}
@ParameterizedTest

View File

@@ -44,8 +44,7 @@ class WebSocketIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -76,9 +75,7 @@ class WebSocketIT extends BaseIT {
Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected);
log.info("connected to {}", session.getRequestURI());
Awaitility.await()
.atMost(15, TimeUnit.SECONDS)
.until(() -> closeReasonRef.get() != null);
Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> closeReasonRef.get() != null);
}
}

View File

@@ -33,8 +33,7 @@ class DatabaseCleaningIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -85,8 +84,7 @@ class DatabaseCleaningIT extends BaseIT {
// Verify the entry is starred
Entries starredEntries = getCategoryEntries(CategoryREST.STARRED);
Assertions.assertEquals(1, starredEntries.getEntries().size());
Assertions.assertEquals(
entryToStar.getId(), starredEntries.getEntries().getFirst().getId());
Assertions.assertEquals(entryToStar.getId(), starredEntries.getEntries().getFirst().getId());
// Run cleanup with capacity of 0 (should delete all non-starred entries)
// With keepStarredEntries=true (default), only non-starred entries are counted for
@@ -99,14 +97,12 @@ class DatabaseCleaningIT extends BaseIT {
// Verify starred entry is still present
Entries starredEntriesAfter = getCategoryEntries(CategoryREST.STARRED);
Assertions.assertEquals(1, starredEntriesAfter.getEntries().size());
Assertions.assertEquals(
entryToStar.getId(), starredEntriesAfter.getEntries().getFirst().getId());
Assertions.assertEquals(entryToStar.getId(), starredEntriesAfter.getEntries().getFirst().getId());
// Verify the non-starred entry was deleted (only starred entry should remain)
Entries entriesAfter = getFeedEntries(subscriptionId);
Assertions.assertEquals(1, entriesAfter.getEntries().size());
Assertions.assertEquals(
entryToStar.getId(), entriesAfter.getEntries().getFirst().getId());
Assertions.assertEquals(entryToStar.getId(), entriesAfter.getEntries().getFirst().getId());
}
@Test
@@ -134,14 +130,12 @@ class DatabaseCleaningIT extends BaseIT {
// Verify starred entry is still present
Entries starredEntriesAfter = getCategoryEntries(CategoryREST.STARRED);
Assertions.assertEquals(1, starredEntriesAfter.getEntries().size());
Assertions.assertEquals(
entryToStar.getId(), starredEntriesAfter.getEntries().getFirst().getId());
Assertions.assertEquals(entryToStar.getId(), starredEntriesAfter.getEntries().getFirst().getId());
// Verify the non-starred entry was deleted
Entries entriesAfter = getFeedEntries(subscriptionId);
Assertions.assertEquals(1, entriesAfter.getEntries().size());
Assertions.assertEquals(
entryToStar.getId(), entriesAfter.getEntries().getFirst().getId());
Assertions.assertEquals(entryToStar.getId(), entriesAfter.getEntries().getFirst().getId());
}
@Test
@@ -183,15 +177,13 @@ class DatabaseCleaningIT extends BaseIT {
starEntry(entry.getId(), subscriptionId);
// Verify entry is starred
Assertions.assertEquals(
1, getCategoryEntries(CategoryREST.STARRED).getEntries().size());
Assertions.assertEquals(1, getCategoryEntries(CategoryREST.STARRED).getEntries().size());
// Unstar the entry
unstarEntry(entry.getId(), subscriptionId);
// Verify entry is no longer starred
Assertions.assertEquals(
0, getCategoryEntries(CategoryREST.STARRED).getEntries().size());
Assertions.assertEquals(0, getCategoryEntries(CategoryREST.STARRED).getEntries().size());
// Run cleanup for entries older than now
Instant olderThan = Instant.now().plus(Duration.ofDays(1));
@@ -212,27 +204,20 @@ class DatabaseCleaningIT extends BaseIT {
// verify we have 2 unread entries
Entries entries = getFeedEntries(subscriptionId);
Assertions.assertEquals(
2, entries.getEntries().stream().filter(e -> !e.isRead()).count());
Assertions.assertEquals(2, entries.getEntries().stream().filter(e -> !e.isRead()).count());
// set auto-mark as read
FeedModificationRequest req = new FeedModificationRequest();
req.setId(subscriptionId);
req.setAutoMarkAsReadAfterDays(1);
RestAssured.given()
.body(req)
.contentType(ContentType.JSON)
.post("rest/feed/modify")
.then()
.statusCode(200);
RestAssured.given().body(req).contentType(ContentType.JSON).post("rest/feed/modify").then().statusCode(200);
// run auto-mark as read
databaseCleaningService.autoMarkAsRead();
// verify all entries are now read
entries = getFeedEntries(subscriptionId);
Assertions.assertEquals(
0, entries.getEntries().stream().filter(e -> !e.isRead()).count());
Assertions.assertEquals(0, entries.getEntries().stream().filter(e -> !e.isRead()).count());
}
}
}

View File

@@ -26,8 +26,7 @@ class AdminIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach

View File

@@ -38,8 +38,7 @@ class CategoryIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -70,8 +69,7 @@ class CategoryIT extends BaseIT {
Assertions.assertEquals("test-category-1", root.getChildren().getFirst().getName());
Assertions.assertEquals(1, root.getChildren().getFirst().getChildren().size());
Assertions.assertEquals(
"modified-category-2",
root.getChildren().getFirst().getChildren().getFirst().getName());
"modified-category-2", root.getChildren().getFirst().getChildren().getFirst().getName());
request = new CategoryModificationRequest();
request.setId(Long.valueOf(category3Id));
@@ -152,9 +150,7 @@ class CategoryIT extends BaseIT {
@Test
void all() {
subscribeAndWaitForEntries(getFeedUrl());
Assertions.assertTrue(
getCategoryEntries(CategoryREST.ALL).getEntries().stream()
.noneMatch(Entry::isRead));
Assertions.assertTrue(getCategoryEntries(CategoryREST.ALL).getEntries().stream().noneMatch(Entry::isRead));
MarkRequest request = new MarkRequest();
request.setId(CategoryREST.ALL);
@@ -165,17 +161,14 @@ class CategoryIT extends BaseIT {
.post("rest/category/mark")
.then()
.statusCode(200);
Assertions.assertTrue(
getCategoryEntries(CategoryREST.ALL).getEntries().stream()
.allMatch(Entry::isRead));
Assertions.assertTrue(getCategoryEntries(CategoryREST.ALL).getEntries().stream().allMatch(Entry::isRead));
}
@Test
void specificCategory() {
String categoryId = createCategory("test-category");
subscribeAndWaitForEntries(getFeedUrl(), categoryId);
Assertions.assertTrue(
getCategoryEntries(categoryId).getEntries().stream().noneMatch(Entry::isRead));
Assertions.assertTrue(getCategoryEntries(categoryId).getEntries().stream().noneMatch(Entry::isRead));
MarkRequest request = new MarkRequest();
request.setId(categoryId);
@@ -186,8 +179,7 @@ class CategoryIT extends BaseIT {
.post("rest/category/mark")
.then()
.statusCode(200);
Assertions.assertTrue(
getCategoryEntries(categoryId).getEntries().stream().allMatch(Entry::isRead));
Assertions.assertTrue(getCategoryEntries(categoryId).getEntries().stream().allMatch(Entry::isRead));
}
}
@@ -233,18 +225,14 @@ class CategoryIT extends BaseIT {
@Test
void starred() {
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
Assertions.assertEquals(
0, getCategoryEntries(CategoryREST.STARRED).getEntries().size());
Assertions.assertEquals(0, getCategoryEntries(CategoryREST.STARRED).getEntries().size());
Entry entry = getFeedEntries(subscriptionId).getEntries().getFirst();
StarRequest starRequest = new StarRequest();
starRequest.setId(entry.getId());
starRequest.setStarred(true);
RestAssured.given()
.body(starRequest)
.contentType(ContentType.JSON)
.post("rest/entry/star");
RestAssured.given().body(starRequest).contentType(ContentType.JSON).post("rest/entry/star");
Entries starredEntries = getCategoryEntries(CategoryREST.STARRED);
Assertions.assertEquals(1, starredEntries.getEntries().size());
@@ -261,10 +249,7 @@ class CategoryIT extends BaseIT {
TagRequest tagRequest = new TagRequest();
tagRequest.setEntryId(Long.valueOf(entry.getId()));
tagRequest.setTags(List.of("my-tag"));
RestAssured.given()
.body(tagRequest)
.contentType(ContentType.JSON)
.post("rest/entry/tag");
RestAssured.given().body(tagRequest).contentType(ContentType.JSON).post("rest/entry/tag");
Entries taggedEntries = getTaggedEntries("my-tag");
Assertions.assertEquals(1, taggedEntries.getEntries().size());
@@ -274,9 +259,7 @@ class CategoryIT extends BaseIT {
@Test
void keywords() {
subscribeAndWaitForEntries(getFeedUrl());
Assertions.assertEquals(
1,
getCategoryEntries(CategoryREST.ALL, "Item 2 description").getEntries().size());
Assertions.assertEquals(1, getCategoryEntries(CategoryREST.ALL, "Item 2 description").getEntries().size());
}
@Test

View File

@@ -48,8 +48,7 @@ class FeedIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -130,22 +129,15 @@ class FeedIT extends BaseIT {
void markWithoutDates() {
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
markFeedEntries(subscriptionId, null, null);
Assertions.assertTrue(
getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
}
@Test
void markOlderThan() {
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
markFeedEntries(
subscriptionId,
LocalDate.of(2023, 12, 28).atStartOfDay().toInstant(ZoneOffset.UTC),
null);
markFeedEntries(subscriptionId, LocalDate.of(2023, 12, 28).atStartOfDay().toInstant(ZoneOffset.UTC), null);
Assertions.assertEquals(
1,
getFeedEntries(subscriptionId).getEntries().stream()
.filter(Entry::isRead)
.count());
1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
}
@Test
@@ -155,8 +147,7 @@ class FeedIT extends BaseIT {
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
markFeedEntries(subscriptionId, null, threshold);
Assertions.assertTrue(
getFeedEntries(subscriptionId).getEntries().stream().noneMatch(Entry::isRead));
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().noneMatch(Entry::isRead));
}
@Test
@@ -167,17 +158,14 @@ class FeedIT extends BaseIT {
Instant threshold = Instant.now().plus(Duration.ofSeconds(1));
markFeedEntries(subscriptionId, null, threshold);
Assertions.assertTrue(
getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
}
private void markFeedEntries(
long subscriptionId, Instant olderThan, Instant insertedBefore) {
private void markFeedEntries(long subscriptionId, Instant olderThan, Instant insertedBefore) {
MarkRequest request = new MarkRequest();
request.setId(String.valueOf(subscriptionId));
request.setOlderThan(olderThan == null ? null : olderThan.toEpochMilli());
request.setInsertedBefore(
insertedBefore == null ? null : insertedBefore.toEpochMilli());
request.setInsertedBefore(insertedBefore == null ? null : insertedBefore.toEpochMilli());
RestAssured.given()
.body(request)
@@ -202,9 +190,7 @@ class FeedIT extends BaseIT {
Awaitility.await()
.atMost(Duration.ofSeconds(15))
.until(
() -> getSubscription(subscriptionId),
f -> f.getLastRefresh().isAfter(threshold));
.until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().isAfter(threshold));
Assertions.assertEquals(2, getCategoryEntries(CategoryREST.ALL).getEntries().size());
Assertions.assertEquals(HttpStatus.SC_TOO_MANY_REQUESTS, forceRefreshAllFeeds());
@@ -274,9 +260,7 @@ class FeedIT extends BaseIT {
.response()
.asByteArray();
byte[] defaultFavicon =
IOUtils.toByteArray(
Objects.requireNonNull(
getClass().getResource("/images/default_favicon.gif")));
IOUtils.toByteArray(Objects.requireNonNull(getClass().getResource("/images/default_favicon.gif")));
Assertions.assertArrayEquals(defaultFavicon, icon);
}
}
@@ -297,8 +281,7 @@ class FeedIT extends BaseIT {
}
void importOpml() {
InputStream stream =
Objects.requireNonNull(getClass().getResourceAsStream("/opml/opml_v2.0.xml"));
InputStream stream = Objects.requireNonNull(getClass().getResourceAsStream("/opml/opml_v2.0.xml"));
RestAssured.given()
.multiPart("file", "opml_v2.0.xml", stream, MediaType.MULTIPART_FORM_DATA)
@@ -355,8 +338,7 @@ class FeedIT extends BaseIT {
.as(Entries.class);
Assertions.assertEquals(3, unreadEntries.getEntries().size());
Assertions.assertTrue(
unreadEntries.getEntries().stream()
.noneMatch(e -> e.getTitle().toLowerCase().contains("item 4")),
unreadEntries.getEntries().stream().noneMatch(e -> e.getTitle().toLowerCase().contains("item 4")),
"Item 4 should be filtered out (marked as read)");
}
}

View File

@@ -32,8 +32,7 @@ class FeverIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
// create api key
ProfileModificationRequest req = new ProfileModificationRequest();
@@ -133,23 +132,11 @@ class FeverIT extends BaseIT {
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
Entry entry = getFeedEntries(subscriptionId).getEntries().getFirst();
client.execute(
"_",
new Param("mark", "item"),
new Param("id", entry.getId()),
new Param("as", "read"));
Assertions.assertEquals(
1,
getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
client.execute("_", new Param("mark", "item"), new Param("id", entry.getId()), new Param("as", "read"));
Assertions.assertEquals(1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
client.execute(
"_",
new Param("mark", "item"),
new Param("id", entry.getId()),
new Param("as", "unread"));
Assertions.assertEquals(
0,
getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
client.execute("_", new Param("mark", "item"), new Param("id", entry.getId()), new Param("as", "unread"));
Assertions.assertEquals(0, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
}
@Test
@@ -162,8 +149,7 @@ class FeverIT extends BaseIT {
new Param("id", String.valueOf(subscriptionId)),
new Param("as", "read"));
Assertions.assertTrue(
getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
}
@Test
@@ -172,13 +158,9 @@ class FeverIT extends BaseIT {
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl(), categoryId);
client.execute(
"_",
new Param("mark", "group"),
new Param("id", String.valueOf(categoryId)),
new Param("as", "read"));
"_", new Param("mark", "group"), new Param("id", String.valueOf(categoryId)), new Param("as", "read"));
Assertions.assertTrue(
getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
}
@Test
@@ -186,27 +168,13 @@ class FeverIT extends BaseIT {
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
Entry entry = getFeedEntries(subscriptionId).getEntries().getFirst();
client.execute(
"_",
new Param("mark", "item"),
new Param("id", entry.getId()),
new Param("as", "saved"));
client.execute("_", new Param("mark", "item"), new Param("id", entry.getId()), new Param("as", "saved"));
Assertions.assertEquals(
1,
getFeedEntries(subscriptionId).getEntries().stream()
.filter(Entry::isStarred)
.count());
1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isStarred).count());
client.execute(
"_",
new Param("mark", "item"),
new Param("id", entry.getId()),
new Param("as", "unsaved"));
client.execute("_", new Param("mark", "item"), new Param("id", entry.getId()), new Param("as", "unsaved"));
Assertions.assertEquals(
0,
getFeedEntries(subscriptionId).getEntries().stream()
.filter(Entry::isStarred)
.count());
0, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isStarred).count());
}
@Test

View File

@@ -42,8 +42,7 @@ class GoogleReaderIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
// create api key
ProfileModificationRequest req = new ProfileModificationRequest();
@@ -144,59 +143,45 @@ class GoogleReaderIT extends BaseIT {
@Test
void subscriptionList() {
subscribe(getFeedUrl());
SubscriptionList list =
client.get(BASE + "/reader/api/0/subscription/list").as(SubscriptionList.class);
SubscriptionList list = client.get(BASE + "/reader/api/0/subscription/list").as(SubscriptionList.class);
Assertions.assertEquals(1, list.getSubscriptions().size());
Assertions.assertEquals(
"my title for this feed", list.getSubscriptions().getFirst().getTitle());
Assertions.assertEquals("my title for this feed", list.getSubscriptions().getFirst().getTitle());
}
@Test
void tagList() {
createCategory("test-category");
TagList tagList = client.get(BASE + "/reader/api/0/tag/list").as(TagList.class);
Assertions.assertTrue(tagList.getTags().stream().anyMatch(t -> t.getId().equals("user/-/label/test-category")));
Assertions.assertTrue(
tagList.getTags().stream()
.anyMatch(t -> t.getId().equals("user/-/label/test-category")));
Assertions.assertTrue(
tagList.getTags().stream()
.anyMatch(t -> t.getId().equals("user/-/state/com.google/starred")));
tagList.getTags().stream().anyMatch(t -> t.getId().equals("user/-/state/com.google/starred")));
}
@Test
void unreadCount() {
subscribeAndWaitForEntries(getFeedUrl());
UnreadCounts counts =
client.get(BASE + "/reader/api/0/unread-count").as(UnreadCounts.class);
UnreadCounts counts = client.get(BASE + "/reader/api/0/unread-count").as(UnreadCounts.class);
Assertions.assertTrue(
counts.getUnreadCounts().stream()
.anyMatch(c ->
c.getId().equals("user/-/state/com.google/reading-list")
&& c.getCount() == 2));
.anyMatch(c -> c.getId().equals("user/-/state/com.google/reading-list") && c.getCount() == 2));
}
@Test
void streamContents() {
subscribeAndWaitForEntries(getFeedUrl());
StreamContents contents =
client.get(BASE + "/reader/api/0/stream/contents/reading-list")
.as(StreamContents.class);
client.get(BASE + "/reader/api/0/stream/contents/reading-list").as(StreamContents.class);
Assertions.assertEquals(2, contents.getItems().size());
Assertions.assertEquals("Item 2", contents.getItems().getFirst().getTitle());
Assertions.assertTrue(
contents.getItems()
.getFirst()
.getId()
.matches("tag:google\\.com,2005:reader/item/[0-9a-f]{16}"));
contents.getItems().getFirst().getId().matches("tag:google\\.com,2005:reader/item/[0-9a-f]{16}"));
}
@Test
void streamItemIds() {
subscribeAndWaitForEntries(getFeedUrl());
ItemRefs refs =
client.get(
BASE
+ "/reader/api/0/stream/items/ids?s=user/-/state/com.google/reading-list")
client.get(BASE + "/reader/api/0/stream/items/ids?s=user/-/state/com.google/reading-list")
.as(ItemRefs.class);
Assertions.assertEquals(2, refs.getItemRefs().size());
}
@@ -211,17 +196,13 @@ class GoogleReaderIT extends BaseIT {
BASE + "/reader/api/0/edit-tag",
Map.of("i", entry.getId(), "a", "user/-/state/com.google/read", "T", token));
Assertions.assertEquals(
1,
getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
Assertions.assertEquals(1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
client.postForm(
BASE + "/reader/api/0/edit-tag",
Map.of("i", entry.getId(), "r", "user/-/state/com.google/read", "T", token));
Assertions.assertEquals(
0,
getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
Assertions.assertEquals(0, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
}
@Test
@@ -232,12 +213,9 @@ class GoogleReaderIT extends BaseIT {
Entry entry = getFeedEntries(subscriptionId).getEntries().getFirst();
client.postForm(
BASE + "/reader/api/0/edit-tag",
Map.of("i", entry.getId(), "a", "user/-/state/com.google/read"));
BASE + "/reader/api/0/edit-tag", Map.of("i", entry.getId(), "a", "user/-/state/com.google/read"));
Assertions.assertEquals(
1,
getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
Assertions.assertEquals(1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
}
@Test
@@ -251,10 +229,7 @@ class GoogleReaderIT extends BaseIT {
Map.of("i", entry.getId(), "a", "user/-/state/com.google/starred", "T", token));
Assertions.assertEquals(
1,
getFeedEntries(subscriptionId).getEntries().stream()
.filter(Entry::isStarred)
.count());
1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isStarred).count());
}
@Test
@@ -266,8 +241,7 @@ class GoogleReaderIT extends BaseIT {
BASE + "/reader/api/0/mark-all-as-read",
Map.of("s", "user/-/state/com.google/reading-list", "T", token));
Assertions.assertTrue(
getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
}
@Test
@@ -276,24 +250,14 @@ class GoogleReaderIT extends BaseIT {
client.postForm(
BASE + "/reader/api/0/subscription/edit",
Map.of(
"ac",
"subscribe",
"s",
"feed/" + getFeedUrl(),
"t",
"new subscription",
"T",
token));
Map.of("ac", "subscribe", "s", "feed/" + getFeedUrl(), "t", "new subscription", "T", token));
SubscriptionList list =
client.get(BASE + "/reader/api/0/subscription/list").as(SubscriptionList.class);
SubscriptionList list = client.get(BASE + "/reader/api/0/subscription/list").as(SubscriptionList.class);
Assertions.assertEquals(1, list.getSubscriptions().size());
String feedStreamId = list.getSubscriptions().getFirst().getId();
client.postForm(
BASE + "/reader/api/0/subscription/edit",
Map.of("ac", "unsubscribe", "s", feedStreamId, "T", token));
BASE + "/reader/api/0/subscription/edit", Map.of("ac", "unsubscribe", "s", feedStreamId, "T", token));
list = client.get(BASE + "/reader/api/0/subscription/list").as(SubscriptionList.class);
Assertions.assertTrue(list.getSubscriptions().isEmpty());
@@ -302,10 +266,7 @@ class GoogleReaderIT extends BaseIT {
private record GoogleReaderClient(String token) {
private RequestSpecification given() {
return RestAssured.given()
.auth()
.none()
.header("Authorization", "GoogleLogin auth=" + token);
return RestAssured.given().auth().none().header("Authorization", "GoogleLogin auth=" + token);
}
Response get(String path) {

View File

@@ -15,12 +15,7 @@ class ServerIT extends BaseIT {
@Test
void getServerInfos() {
ServerInfo serverInfos =
RestAssured.given()
.get("/rest/server/get")
.then()
.statusCode(200)
.extract()
.as(ServerInfo.class);
RestAssured.given().get("/rest/server/get").then().statusCode(200).extract().as(ServerInfo.class);
Assertions.assertTrue(serverInfos.isAllowRegistrations());
Assertions.assertTrue(serverInfos.isSmtpEnabled());
Assertions.assertTrue(serverInfos.isDemoAccountEnabled());

View File

@@ -39,8 +39,7 @@ class UserIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
mailbox.clear();
}
@@ -52,8 +51,7 @@ class UserIT extends BaseIT {
@Test
void resetPassword() {
String session =
login().stream().map(HttpCookie::toString).collect(Collectors.joining(";"));
String session = login().stream().map(HttpCookie::toString).collect(Collectors.joining(";"));
PasswordResetRequest req = new PasswordResetRequest();
req.setEmail("admin@commafeed.com");
@@ -70,9 +68,7 @@ class UserIT extends BaseIT {
MailMessage message = mails.getFirst();
Assertions.assertEquals("CommaFeed - Password recovery", message.getSubject());
Assertions.assertTrue(
message.getHtml()
.startsWith("You asked for password recovery for account 'admin'"));
Assertions.assertTrue(message.getHtml().startsWith("You asked for password recovery for account 'admin'"));
Assertions.assertTrue(message.getHtml().contains("https://commafeed.example.com"));
Assertions.assertEquals("admin@commafeed.com", message.getTo().getFirst());
@@ -116,8 +112,7 @@ class UserIT extends BaseIT {
.then()
.statusCode(401);
RestAssured.authentication =
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, newPassword);
RestAssured.authentication = RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, newPassword);
RestAssured.given().get("rest/user/settings").then().statusCode(200);
}
@@ -156,14 +151,12 @@ class UserIT extends BaseIT {
Elements links = Jsoup.parse(html).select("a");
Assertions.assertEquals(1, links.size());
Assertions.assertTrue(
links.getFirst().attr("href").startsWith("https://commafeed.example.com"));
Assertions.assertTrue(links.getFirst().attr("href").startsWith("https://commafeed.example.com"));
}
@Test
void saveSettings() {
Settings settings =
RestAssured.given().get("rest/user/settings").then().extract().as(Settings.class);
Settings settings = RestAssured.given().get("rest/user/settings").then().extract().as(Settings.class);
settings.setLanguage("test");
RestAssured.given()
.body(settings)
@@ -172,8 +165,7 @@ class UserIT extends BaseIT {
.then()
.statusCode(200);
Settings updatedSettings =
RestAssured.given().get("rest/user/settings").then().extract().as(Settings.class);
Settings updatedSettings = RestAssured.given().get("rest/user/settings").then().extract().as(Settings.class);
Assertions.assertEquals("test", updatedSettings.getLanguage());
}
}

View File

@@ -21,8 +21,7 @@ class CustomCodeIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach
@@ -34,12 +33,7 @@ class CustomCodeIT extends BaseIT {
void test() {
// get settings
Settings settings =
RestAssured.given()
.get("rest/user/settings")
.then()
.statusCode(200)
.extract()
.as(Settings.class);
RestAssured.given().get("rest/user/settings").then().statusCode(200).extract().as(Settings.class);
// update settings
settings.setCustomJs("custom-js");
@@ -52,11 +46,7 @@ class CustomCodeIT extends BaseIT {
.statusCode(HttpStatus.SC_OK);
// check custom code servlets
RestAssured.given()
.get("custom_js.js")
.then()
.statusCode(HttpStatus.SC_OK)
.body(CoreMatchers.is("custom-js"));
RestAssured.given().get("custom_js.js").then().statusCode(HttpStatus.SC_OK).body(CoreMatchers.is("custom-js"));
RestAssured.given()
.get("custom_css.css")
.then()

View File

@@ -33,9 +33,7 @@ class LogoutIT extends BaseIT {
RestAssured.given()
.header(
HttpHeaders.COOKIE,
cookies.stream()
.map(HttpCookie::toString)
.collect(Collectors.joining(";")))
cookies.stream().map(HttpCookie::toString).collect(Collectors.joining(";")))
.redirects()
.follow(false)
.get("logout")
@@ -46,8 +44,6 @@ class LogoutIT extends BaseIT {
List<String> setCookieHeaders = responseHeaders.getValues(HttpHeaders.SET_COOKIE);
Assertions.assertTrue(
setCookieHeaders.stream()
.flatMap(c -> HttpCookie.parse(c).stream())
.allMatch(c -> c.getMaxAge() == 0));
setCookieHeaders.stream().flatMap(c -> HttpCookie.parse(c).stream()).allMatch(c -> c.getMaxAge() == 0));
}
}

View File

@@ -20,8 +20,7 @@ class NextUnreadIT extends BaseIT {
void setup() {
initialSetup(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.authentication =
RestAssured.preemptive()
.basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
}
@AfterEach

View File

@@ -15,8 +15,7 @@ class CommaFeedPropertiesGeneratorTest {
@Test
void testGenerate() throws Exception {
InputStream model = getClass().getResourceAsStream("/properties/quarkus-config-model.yaml");
InputStream javadoc =
getClass().getResourceAsStream("/properties/quarkus-config-javadoc.yaml");
InputStream javadoc = getClass().getResourceAsStream("/properties/quarkus-config-javadoc.yaml");
URL output = getClass().getResource("/properties/output.properties");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new CommaFeedPropertiesGenerator().generate(model, javadoc, baos);