From 670913698776e09b7ff44f44ccdcf56303d79be3 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 6 Sep 2018 13:58:40 +0300 Subject: merge legacy www --- .../java/com/juick/server/tests/ServerTests.java | 110 ++--- .../java/com/juick/server/tests/WebAppTests.java | 466 +++++++++++++++++++++ 2 files changed, 521 insertions(+), 55 deletions(-) create mode 100644 juick-server/src/test/java/com/juick/server/tests/WebAppTests.java (limited to 'juick-server/src/test/java/com/juick/server') diff --git a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java index 1931f13b..fc18dbf5 100644 --- a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java +++ b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java @@ -368,19 +368,19 @@ public class ServerTests { @Test public void testAllUnAuthorized() throws Exception { - mockMvc.perform(get("/")) + mockMvc.perform(get("/api/")) .andExpect(status().isMovedPermanently()); - mockMvc.perform(get("/auth")) + mockMvc.perform(get("/api/auth")) .andExpect(status().isUnauthorized()); - mockMvc.perform(get("/home")) + mockMvc.perform(get("/api/home")) .andExpect(status().isUnauthorized()); - mockMvc.perform(get("/messages/recommended")) + mockMvc.perform(get("/api/messages/recommended")) .andExpect(status().isUnauthorized()); - mockMvc.perform(get("/messages/set_privacy")) + mockMvc.perform(get("/api/messages/set_privacy")) .andExpect(status().isUnauthorized()); } @@ -392,7 +392,7 @@ public class ServerTests { Message msg = messagesService.getMessage(mid); tagService.createTag("тест"); mockMvc.perform( - get("/home") + get("/api/home") .with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) @@ -411,12 +411,12 @@ public class ServerTests { public void homeTestWithMessagesAndRememberMe() throws Exception { String ugnichHash = userService.getHashByUID(ugnich.getUid()); mockMvc.perform( - get("/home") + get("/api/home") .with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()) .andReturn(); - mockMvc.perform(get("/home") + mockMvc.perform(get("/api/home") .param("hash", ugnichHash)) .andExpect(status().isOk()); } @@ -424,7 +424,7 @@ public class ServerTests { @Test public void homeTestWithMessagesAndSimpleCors() throws Exception { mockMvc.perform( - get("/home") + get("/api/home") .with(httpBasic(ugnichName, ugnichPassword)) .header("Origin", "http://api.example.net")) .andExpect(status().isOk()) @@ -434,7 +434,7 @@ public class ServerTests { @Test public void homeTestWithPreflightCors() throws Exception { mockMvc.perform( - options("/home") + options("/api/home") .with(httpBasic(ugnichName, ugnichPassword)) .header("Origin", "http://api.example.net") .header("Access-Control-Request-Method", "POST") @@ -449,10 +449,10 @@ public class ServerTests { public void anonymousApis() throws Exception { - mockMvc.perform(get("/messages")) + mockMvc.perform(get("/api/messages")) .andExpect(status().isOk()); - mockMvc.perform(get("/users") + mockMvc.perform(get("/api/users") .param("uname", "ugnich") .param("uname", "freefd")) .andExpect(status().isOk()) @@ -473,7 +473,7 @@ public class ServerTests { messagesService.likeMessage(mid, freefdId, 2 ); messagesService.likeMessage(mid, freefdId, 3 ); - mockMvc.perform(get("/messages?"+ "hash=" + userIdHash)) + mockMvc.perform(get("/api/messages?"+ "hash=" + userIdHash)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) @@ -482,7 +482,7 @@ public class ServerTests { .andExpect((jsonPath("$[0].reactions[?(@.id == 2)].count", is(Collections.singletonList(2))))); - mockMvc.perform(get("/reactions?hash=" + userIdHash)) + mockMvc.perform(get("/api/reactions?hash=" + userIdHash)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) .andExpect(jsonPath("$.length()", is(7))); @@ -494,14 +494,14 @@ public class ServerTests { Tag yo = tagService.getTag("yo", true); messagesService.createMessage(ugnich.getUid(), "text", null, Arrays.asList(yo, weather)); messagesService.createMessage(freefd.getUid(), "text2", null, Collections.singletonList(yo)); - MvcResult result = mockMvc.perform(get("/tags")) + MvcResult result = mockMvc.perform(get("/api/tags")) .andExpect(status().isOk()) .andReturn(); List tagsFromApi = jsonMapper.readValue(result.getResponse().getContentAsString(), new TypeReference>(){}); TagStats yoStats = tagsFromApi.stream().filter(t -> t.getTag().getName().equals("yo")).findFirst().get(); assertThat(yoStats.getUsageCount(), is(2)); - MvcResult result2 = mockMvc.perform(get("/tags") + MvcResult result2 = mockMvc.perform(get("/api/tags") .param("user_id", String.valueOf(ugnich.getUid()))) .andExpect(status().isOk()) .andReturn(); @@ -513,40 +513,40 @@ public class ServerTests { @Test public void postWithReferer() throws Exception { - mockMvc.perform(post("/post") + mockMvc.perform(post("/api/post") .param("body", "yo") .with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()); } @Test public void threadWithEphemeralNumberShouldReturn404() throws Exception { - mockMvc.perform(get("/thread").param("mid", "999999999") + mockMvc.perform(get("/api/thread").param("mid", "999999999") .with(httpBasic(ugnichName, ugnichPassword))).andExpect(status().is4xxClientError()); } @Test public void performRequestsWithIssuedToken() throws Exception { String ugnichHash = userService.getHashByUID(ugnich.getUid()); - mockMvc.perform(get("/home")).andExpect(status().isUnauthorized()); - mockMvc.perform(get("/auth")) + mockMvc.perform(get("/api/home")).andExpect(status().isUnauthorized()); + mockMvc.perform(get("/api/auth")) .andExpect(status().isUnauthorized()); - mockMvc.perform(get("/auth").with(httpBasic(ugnichName, "wrongpassword"))) + mockMvc.perform(get("/api/auth").with(httpBasic(ugnichName, "wrongpassword"))) .andExpect(status().isUnauthorized()); - MvcResult result = mockMvc.perform(get("/auth").with(httpBasic(ugnichName, ugnichPassword))) + MvcResult result = mockMvc.perform(get("/api/auth").with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()) .andReturn(); String authHash = result.getResponse().getContentAsString(); assertThat(authHash, equalTo(ugnichHash)); - mockMvc.perform(get("/home").param("hash", ugnichHash)).andExpect(status().isOk()); + mockMvc.perform(get("/api/home").param("hash", ugnichHash)).andExpect(status().isOk()); } @Test public void registerForNotificationsTests() throws Exception { String token = "123456"; ExternalToken registration = new ExternalToken(null, "apns", token, null); - mockMvc.perform(put("/notifications").with(httpBasic(ugnichName, ugnichPassword)) + mockMvc.perform(put("/api/notifications").with(httpBasic(ugnichName, ugnichPassword)) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(jsonMapper.writeValueAsBytes(Collections.singletonList(registration)))) .andExpect(status().isOk()); - MvcResult result = mockMvc.perform(get("/notifications") + MvcResult result = mockMvc.perform(get("/api/notifications") .param("uid", String.valueOf(ugnich.getUid())) .with(httpBasic(juickName, juickPassword))) .andExpect(status().isOk()) @@ -565,10 +565,10 @@ public class ServerTests { @Test public void notificationsTokensTest() throws Exception { List tokens = Collections.singletonList(new ExternalToken(null, "gcm", "123456", null)); - mockMvc.perform(delete("/notifications").with(httpBasic(ugnichName, ugnichPassword)) + mockMvc.perform(delete("/api/notifications").with(httpBasic(ugnichName, ugnichPassword)) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(jsonMapper.writeValueAsBytes(tokens))).andExpect(status().isForbidden()); - mockMvc.perform(delete("/notifications").with(httpBasic(juickName, juickPassword)) + mockMvc.perform(delete("/api/notifications").with(httpBasic(juickName, juickPassword)) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(jsonMapper.writeValueAsBytes(tokens))).andExpect(status().isOk()); } @@ -576,9 +576,9 @@ public class ServerTests { public void notificationsSettingsAllowedOnlyForServiceUser() throws Exception { CommandResult result = commandsManager.processCommand(ugnich, "yo", emptyUri); String stringValueOfMid = String.valueOf(result.getNewMessage().get().getMid()); - mockMvc.perform(get("/notifications").with(httpBasic(juickName, juickPassword)) + mockMvc.perform(get("/api/notifications").with(httpBasic(juickName, juickPassword)) .param("mid", stringValueOfMid).param("uid", String.valueOf(ugnich.getUid()))).andExpect(status().isOk()); - mockMvc.perform(get("/notifications") + mockMvc.perform(get("/api/notifications") .param("mid", stringValueOfMid).param("uid", String.valueOf(ugnich.getUid()))).andExpect(status().isUnauthorized()); } @Test @@ -858,7 +858,7 @@ public class ServerTests { "
s2313334
\n" + "\n" + "--001a11454886e42be5056786ca70--"; - mockMvc.perform(post("/mail").with(httpBasic(juickName, juickPassword)).content(mail)) + mockMvc.perform(post("/api/mail").with(httpBasic(juickName, juickPassword)).content(mail)) .andExpect(status().isOk()); } @@ -869,14 +869,14 @@ public class ServerTests { String freefdHash = userService.getHashByUID(freefd.getUid()); int freefdMid = messagesService.createMessage(freefd.getUid(), "to be not liked", null, null); - mockMvc.perform(post("/like?mid=" + mid + "&hash=" + freefdHash)) + mockMvc.perform(post("/api/like?mid=" + mid + "&hash=" + freefdHash)) .andExpect(status().isOk()) .andExpect(jsonPath("$.status", is("Message is added to your recommendations"))); - mockMvc.perform(get("/thread?mid=" + mid + "&hash=" + freefdHash)) + mockMvc.perform(get("/api/thread?mid=" + mid + "&hash=" + freefdHash)) .andExpect(status().isOk()) .andExpect(jsonPath("$[0].recommendations.length()", is(1))) .andExpect(jsonPath("$[0].recommendations[0]", is(freefdName))); - mockMvc.perform(post("/like?mid=" + freefdMid + "&hash=" + freefdHash)) + mockMvc.perform(post("/api/like?mid=" + freefdMid + "&hash=" + freefdHash)) .andExpect(status().isForbidden()); } @@ -886,7 +886,7 @@ public class ServerTests { String freefdHash = userService.getHashByUID(freefd.getUid()); int mid1 = messagesService.createMessage(user_id, "yo", null, new ArrayList<>()); - mockMvc.perform(post("/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=2")) + mockMvc.perform(post("/api/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=2")) .andExpect(status().isOk()); Message msg4 = messagesService.getMessage(mid1); @@ -894,9 +894,9 @@ public class ServerTests { assertThat(messagesService.getMessages(AnonymousUser.INSTANCE, Collections.singletonList(mid1)).get(0).getLikes(), is(0)); Assert.assertEquals(1, msg4.getReactions().stream().filter(r -> r.getId() == 2) .findFirst().orElseThrow(IllegalStateException::new).getCount()); - mockMvc.perform(post("/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=1")) + mockMvc.perform(post("/api/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=1")) .andExpect(status().isOk()); - mockMvc.perform(post("/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=1")) + mockMvc.perform(post("/api/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=1")) .andExpect(status().isOk()); assertThat(messagesService.getMessage(mid1).getLikes(), is(1)); } @@ -920,7 +920,7 @@ public class ServerTests { assertThat(lastRead.apply(ugnich, mid), is(1)); String ugnichHash = userService.getHashByUID(ugnich.getUid()); int freefdrid = messagesService.createReply(mid, 0, freefd, "again", null); - mockMvc.perform(get(String.format("/thread/mark_read/%d-%d.gif?hash=%s", mid, freefdrid, ugnichHash))) + mockMvc.perform(get(String.format("/api/thread/mark_read/%d-%d.gif?hash=%s", mid, freefdrid, ugnichHash))) .andExpect(status().isOk()) .andExpect(content().bytes(IOUtils.toByteArray( Objects.requireNonNull(getClass().getClassLoader().getResource("Transparent.gif"))))); @@ -934,7 +934,7 @@ public class ServerTests { privacyQueriesService.blacklistUser(ugnich, freefd); newfreefdrid = messagesService.createReply(mid, 0, freefd, "after ban", null); assertThat(lastRead.apply(ugnich, mid), lessThan(newfreefdrid)); - mockMvc.perform(get(String.format("/thread?mid=%d&hash=%s", mid, ugnichHash))) + mockMvc.perform(get(String.format("/api/thread?mid=%d&hash=%s", mid, ugnichHash))) .andExpect(status().isOk()); assertThat(lastRead.apply(ugnich, mid), is(newfreefdrid)); } @@ -1035,13 +1035,13 @@ public class ServerTests { map.add("body", "yo"); map.add("hash", userService.getHashByUID(ugnich.getUid())); ResponseEntity result = restTemplate.postForEntity( - "/post", + "/api/post", request, CommandResult.class); assertThat(result.getStatusCode(), is(HttpStatus.OK)); } @Test public void emptyAuthenticatedPostShouldThrowBadRequest() throws Exception { - mockMvc.perform(post("/post") + mockMvc.perform(post("/api/post") .with(httpBasic(juickName, juickPassword))) .andExpect(status().isBadRequest()); } @@ -1061,7 +1061,7 @@ public class ServerTests { commandsManager.processCommand(ugnich, "S @freefd", emptyUri); assertThat(userService.getUserReaders(ugnich.getUid()).size(), is(1)); String hash = userService.getHashByUID(ugnich.getUid()); - mockMvc.perform(get("/me") + mockMvc.perform(get("/api/me") .with(httpBasic(ugnichName, ugnichPassword))) .andExpect(jsonPath("$.hash", is(hash))) .andExpect(jsonPath("$.readers.length()", is(1))) @@ -1148,7 +1148,7 @@ public class ServerTests { } @Test public void messageEditingSpec() throws Exception { - MvcResult result = mockMvc.perform(post("/post").with(httpBasic(ugnichName, ugnichPassword)) + MvcResult result = mockMvc.perform(post("/api/post").with(httpBasic(ugnichName, ugnichPassword)) .param("body", "YO")).andExpect(status().is2xxSuccessful()).andReturn(); Message original = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class) .getNewMessage().get(); @@ -1156,17 +1156,17 @@ public class ServerTests { assertThat(original.getUpdatedAt(), equalTo(original.getTimestamp())); // to have updated_at greater than ts Thread.sleep(1000); - result = mockMvc.perform(post("/update").with(httpBasic(ugnichName, ugnichPassword)) + result = mockMvc.perform(post("/api/update").with(httpBasic(ugnichName, ugnichPassword)) .param("mid", String.valueOf(original.getMid())) .param("body", "PEOPLE")).andExpect(status().is2xxSuccessful()).andReturn(); Message edited = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class) .getNewMessage().get(); assertThat(edited.getText(), equalTo("PEOPLE")); assertThat(edited.getUpdatedAt(), greaterThan(edited.getTimestamp())); - mockMvc.perform(post("/update").with(httpBasic(freefdName, freefdPassword)) + mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword)) .param("mid", String.valueOf(original.getMid())) .param("body", "PEOPLE")).andExpect(status().is(403)); - result = mockMvc.perform(post("/comment").with(httpBasic(freefdName, freefdPassword)) + result = mockMvc.perform(post("/api/comment").with(httpBasic(freefdName, freefdPassword)) .param("mid", String.valueOf(original.getMid())) .param("body", "HEY")).andExpect(status().is2xxSuccessful()).andReturn(); Message comment = jsonMapper.readValue(result.getResponse().getContentAsString(), Message.class); @@ -1174,7 +1174,7 @@ public class ServerTests { assertThat(comment.getUpdatedAt(), is(comment.getTimestamp())); // to have updated_at greater than ts Thread.sleep(1000); - result = mockMvc.perform(post("/update").with(httpBasic(freefdName, freefdPassword)) + result = mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword)) .param("mid", String.valueOf(comment.getMid())) .param("rid", String.valueOf(comment.getRid())) .param("body", "HEY, JOE")).andExpect(status().is2xxSuccessful()).andReturn(); @@ -1223,7 +1223,7 @@ public class ServerTests { public void xmppStatusApi() throws Exception { Supplier getStatus = () -> { try { - MvcResult result = mockMvc.perform(get("/xmpp/status").with(httpBasic(ugnichName, ugnichPassword))) + MvcResult result = mockMvc.perform(get("/api/xmpp-status").with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()).andReturn(); return jsonMapper.readValue(result.getResponse().getContentAsString(), XMPPStatus.class); } catch (Exception e) { @@ -1273,16 +1273,16 @@ public class ServerTests { User isilmine = userService.getUserByUID(userService.createUser(userName, userPassword)).orElseThrow(IllegalStateException::new); int mid = messagesService.createMessage(isilmine.getUid(), msgText, null, null); - mockMvc.perform(get(String.format("/thread?mid=%d", mid)).with(httpBasic(ugnichName, ugnichPassword))) + mockMvc.perform(get(String.format("/api/thread?mid=%d", mid)).with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()); jdbcTemplate.update("UPDATE users SET banned=1 WHERE id=?", isilmine.getUid()); - mockMvc.perform(get(String.format("/thread?mid=%d", mid)).with(httpBasic(ugnichName, ugnichPassword))) + mockMvc.perform(get(String.format("/api/thread?mid=%d", mid)).with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isNotFound()); - mockMvc.perform(get("/messages?uname=isilmine").with(httpBasic(ugnichName, ugnichPassword))) + mockMvc.perform(get("/api/messages?uname=isilmine").with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isNotFound()); - mockMvc.perform(get("/info/isilmine").with(httpBasic(ugnichName, ugnichPassword))) + mockMvc.perform(get("/api/info/isilmine").with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isNotFound()); - mockMvc.perform(get("/info/ugnich").with(httpBasic(ugnichName, ugnichPassword))) + mockMvc.perform(get("/api/info/ugnich").with(httpBasic(ugnichName, ugnichPassword))) .andExpect(status().isOk()); } @@ -1293,7 +1293,7 @@ public class ServerTests { userService.createUser(userName, userPassword); - mockMvc.perform(get("/auth").with(httpBasic(userName, userPassword))).andExpect(status().isUnauthorized()); + mockMvc.perform(get("/api/auth").with(httpBasic(userName, userPassword))).andExpect(status().isUnauthorized()); } @Test public void bannedUserShouldBeShadowedFromRecommendationsList() throws IOException { @@ -1342,7 +1342,7 @@ public class ServerTests { } @Test public void userProfileAndBlogShouldBeExposedAsActivityStream() throws Exception { - mockMvc.perform(get("/u/ugnich").accept(ActivityObject.LD_JSON_MEDIA_TYPE)) + mockMvc.perform(get("/api/u/ugnich").accept(ActivityObject.LD_JSON_MEDIA_TYPE)) .andExpect(status().isOk()) .andExpect(jsonPath("$.icon.url", is("http://localhost:8080/i/a/1.png"))) .andExpect(jsonPath("$.publicKey.publicKeyPem", is(keystoreManager.getPublicKey()))); @@ -1352,7 +1352,7 @@ public class ServerTests { String.format("message %d", i), null, null)) .collect(Collectors.toCollection(ArrayDeque::new)).descendingIterator()); List midsPage = mids.stream().limit(20).collect(Collectors.toList()); - mockMvc.perform(get("/u/ugnich/blog").accept(ActivityObject.ACTIVITY_JSON_MEDIA_TYPE)) + mockMvc.perform(get("/api/u/ugnich/blog").accept(ActivityObject.ACTIVITY_JSON_MEDIA_TYPE)) .andExpect(status().isOk()) .andExpect(jsonPath("$.orderedItems", hasSize(20))) .andExpect(jsonPath("$.next", is("http://localhost:8080/u/ugnich/blog?before=" + midsPage.get(midsPage.size() - 1)))); diff --git a/juick-server/src/test/java/com/juick/server/tests/WebAppTests.java b/juick-server/src/test/java/com/juick/server/tests/WebAppTests.java new file mode 100644 index 00000000..456c5f32 --- /dev/null +++ b/juick-server/src/test/java/com/juick/server/tests/WebAppTests.java @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.tests; + +import com.gargoylesoftware.htmlunit.CookieManager; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.css.StyleElement; +import com.gargoylesoftware.htmlunit.html.DomElement; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.juick.Message; +import com.juick.Tag; +import com.juick.User; +import com.juick.server.www.Utils; +import com.juick.server.www.WebApp; +import com.juick.service.*; +import com.juick.util.MessageUtils; +import com.mitchellbosecke.pebble.PebbleEngine; +import com.mitchellbosecke.pebble.error.PebbleException; +import com.mitchellbosecke.pebble.template.PebbleTemplate; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.util.FileSystemUtils; + +import javax.inject.Inject; +import javax.servlet.http.Cookie; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.StreamSupport; + +import static junit.framework.TestCase.assertTrue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Created by vitalyster on 12.01.2017. + */ +@RunWith(SpringRunner.class) +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@TestPropertySource(properties = {"ios_app_id=12345678.com.juick.ExampleApp"}) +public class WebAppTests { + @MockBean + private ImagesService imagesService; + @Inject + private WebApp webApp; + + @Inject + private MockMvc mockMvc; + @Inject + private WebClient webClient; + + @Inject + private UserService userService; + @Inject + private MessagesService messagesService; + @Inject + private PrivacyQueriesService privacyQueriesService; + @Inject + private JdbcTemplate jdbcTemplate; + @Inject + private SubscriptionService subscriptionService; + @Inject + private ApplicationEventPublisher applicationEventPublisher; + + @Inject + private PebbleEngine pebbleEngine; + @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") + private String imgPath; + @Value("${ios_app_id:}") + private String appId; + + private static User ugnich, freefd; + private static String ugnichName, ugnichPassword, freefdName, freefdPassword; + + private static boolean isSetUp = false; + + @Before + public void setup() throws IOException { + if (!isSetUp) { + webClient.getOptions().setJavaScriptEnabled(false); + webClient.getOptions().setCssEnabled(false); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + + ugnichName = "ugnich"; + ugnichPassword = "secret"; + freefdName = "freefd"; + freefdPassword = "MyPassw0rd!"; + + userService.createUser(ugnichName, ugnichPassword); + ugnich = userService.getUserByName(ugnichName); + int freefdId = userService.createUser(freefdName, freefdPassword); + freefd = userService.getUserByUID(freefdId).orElseThrow(IllegalStateException::new); + + isSetUp = true; + } + Files.createDirectory(Paths.get(imgPath, "p")); + Files.createDirectory(Paths.get(imgPath, "photos-1024")); + Files.createDirectory(Paths.get(imgPath, "photos-512")); + Files.createDirectory(Paths.get(imgPath, "ps")); + } + + @After + public void teardown() throws IOException { + FileSystemUtils.deleteRecursively(Paths.get(imgPath, "p")); + FileSystemUtils.deleteRecursively(Paths.get(imgPath, "photos-1024")); + FileSystemUtils.deleteRecursively(Paths.get(imgPath, "photos-512")); + FileSystemUtils.deleteRecursively(Paths.get(imgPath, "ps")); + } + + @Test + public void postWithoutTagsShouldNotHaveAsteriskInTitle() throws Exception { + String msgText = "Привет, я - Угнич"; + int mid = messagesService.createMessage(ugnich.getUid(), msgText, null, null); + HtmlPage threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); + assertThat(threadPage.getTitleText(), equalTo("ugnich:")); + } + @Test + public void bannedUserBlogandPostShouldReturn404() throws IOException { + String userName = "isilmine"; + String userPassword = "secret"; + String msgText = "автор этого поста был забанен"; + String hash = "12345678"; + + User isilmine = userService.getUserByUID(userService.createUser(userName, userPassword)).orElseThrow(IllegalStateException::new); + int mid = messagesService.createMessage(isilmine.getUid(), msgText, null, null); + jdbcTemplate.update("UPDATE users SET banned=1 WHERE id=?", isilmine.getUid()); + Page blogPage = webClient.getPage("http://localhost:8080/isilmine"); + Page threadPage = webClient.getPage(String.format("http://localhost:8080/isilmine/%d", mid)); + assertThat(blogPage.getWebResponse().getStatusCode(), equalTo(404)); + assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(404)); + } + + @Test + public void emptyPasswordMeansUserIsDisabledForWeb() throws Exception { + String userName = "oldschooluser"; + String userPassword = ""; + + User daddy = userService.getUserByUID(userService.createUser(userName, userPassword)).orElseThrow(IllegalStateException::new); + + mockMvc.perform(post("/login") + .param("username", userName) + .param("password", userPassword)).andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/login?error=1")); + } + @Test + public void repliesList() throws IOException { + int mid = messagesService.createMessage(ugnich.getUid(), "hello", null, null); + IntStream.range(1, 15).forEach(i -> + messagesService.createReply(mid, i-1, freefd, String.valueOf(i-1), null )); + + HtmlPage threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); + assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(200)); + Long visibleItems = StreamSupport.stream(threadPage.getHtmlElementById("replies") + .getChildElements().spliterator(), false).filter(e -> { + StyleElement display = e.getStyleElement("display"); + return display == null || !display.getValue().equals("none"); + }).count(); + assertThat(visibleItems, equalTo(14L)); + } + @Test + public void userShouldNotSeeReplyButtonToBannedUser() throws Exception { + int mid = messagesService.createMessage(ugnich.getUid(), "freefd bl me", null, null); + messagesService.createReply(mid, 0, ugnich, "yo", null); + MvcResult loginResult = mockMvc.perform(post("/login") + .param("username", freefdName) + .param("password", freefdPassword)) + .andExpect(status().isFound()).andReturn(); + Cookie loginCookie = loginResult.getResponse().getCookie("juick-remember-me"); + webClient.setCookieManager(new CookieManager()); + webClient.getCookieManager().addCookie( + new com.gargoylesoftware.htmlunit.util.Cookie(loginCookie.getDomain(), + loginCookie.getName(), + loginCookie.getValue())); + HtmlPage threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); + assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(200)); + assertThat(threadPage.querySelectorAll(".msg-comment-target").isEmpty(), equalTo(false)); + assertThat(threadPage.querySelectorAll(".a-thread-comment").isEmpty(), equalTo(false)); + privacyQueriesService.blacklistUser(freefd, ugnich); + assertThat(userService.isInBLAny(freefd.getUid(), ugnich.getUid()), equalTo(true)); + int renhaId = userService.createUser("renha", "secret"); + messagesService.createReply(mid, 0, userService.getUserByUID(renhaId).orElseThrow(IllegalStateException::new), + "people", null); + threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); + assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(200)); + assertThat(threadPage.querySelectorAll(".msg-comment-target").isEmpty(), equalTo(true)); + assertThat(threadPage.querySelectorAll(".a-thread-comment").isEmpty(), equalTo(true)); + } + @Test + public void correctTagsEscaping() throws PebbleException, IOException { + PebbleTemplate template = pebbleEngine.getTemplate("views/test"); + Writer writer = new StringWriter(); + template.evaluate(writer, + Collections.singletonMap("tagsList", + Collections.singletonList(StringEscapeUtils.escapeHtml4(new Tag(">_<").getName())))); + String output = writer.toString().trim(); + assertThat(output, equalTo(">_<")); + } + + public DomElement fetchMeta(String url, String name) throws IOException { + HtmlPage page = webClient.getPage(url); + DomElement emptyMeta = new DomElement("", "meta", null, null); + return page.getElementsByTagName("meta").stream() + .filter(t -> t.getAttribute("name").equals(name)).findFirst().orElse(emptyMeta); + } + @Test + public void testTwitterCards() throws Exception { + + int mid = messagesService.createMessage(ugnich.getUid(), "without image", null, null); + + assertThat(fetchMeta(String.format("http://localhost:8080/ugnich/%d", mid), "twitter:card") + .getAttribute("content"), equalTo("summary")); + int mid2 = messagesService.createMessage(ugnich.getUid(), "with image", "png", null); + Message message = messagesService.getMessage(mid2); + assertThat(fetchMeta(String.format("http://localhost:8080/ugnich/%d", mid2), "twitter:card") + .getAttribute("content"), equalTo("summary_large_image")); + assertThat(fetchMeta(String.format("http://localhost:8080/ugnich/%d", mid2), "og:description") + .getAttribute("content"), + startsWith(StringEscapeUtils.escapeHtml4(MessageUtils.getMessageHashTags(message)))); + } + @Test + public void postMessageTests() throws Exception { + mockMvc.perform(post("/post2").param("body", "yo")) + .andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("http://localhost/login")); + MvcResult loginResult = mockMvc.perform(post("/login") + .param("username", ugnichName) + .param("password", ugnichPassword)).andReturn(); + String msgText = "yoppppl"; + mockMvc.perform(post("/post2") + .cookie(loginResult.getResponse().getCookies()) + .param("body", msgText)).andExpect(status().isFound()); + Message lastMessage = messagesService.getMessage(messagesService.getMyFeed(ugnich.getUid(), 0, false).get(0)); + assertThat(lastMessage.getText(), equalTo(msgText)); + mockMvc.perform(post("/post2") + .cookie(loginResult.getResponse().getCookies()) + .param("img", "http://static.juick.com/settings/facebook.png")).andExpect(status().isFound()); + lastMessage = messagesService.getMessage(messagesService.getMyFeed(ugnich.getUid(), 0, false).get(0)); + assertThat(lastMessage.getAttachmentType(), equalTo("png")); + mockMvc.perform(post("/post2") + .cookie(loginResult.getResponse().getCookies()) + .param("img", "bad_url")).andExpect(status().isBadRequest()); + FileInputStream fi = new FileInputStream(new ClassPathResource("static/tagscloud.png").getFile()); + MockMultipartFile file = new MockMultipartFile("attach", fi); + mockMvc.perform(multipart("/post2") + .file(file) + .cookie(loginResult.getResponse().getCookies())).andExpect(status().isFound()); + int mid = messagesService.createMessage(ugnich.getUid(), "dummy message", null, null); + mockMvc.perform(post("/comment") + .param("mid", String.valueOf(mid)) + .param("body", "yo")).andExpect(redirectedUrl("http://localhost/login")); + mockMvc.perform(post("/comment") + .cookie(loginResult.getResponse().getCookies()) + .param("wrong_param", "yo")).andExpect(status().isBadRequest()); + mockMvc.perform(post("/comment") + .cookie(loginResult.getResponse().getCookies()) + .param("mid", String.valueOf(mid)) + .param("wrong_param", "yo")).andExpect(status().isBadRequest()); + mockMvc.perform(post("/comment") + .cookie(loginResult.getResponse().getCookies()) + .param("mid", String.valueOf(mid)) + .param("img", "http://static.juick.com/settings/facebook.png")).andExpect(status().isFound()); + mockMvc.perform(multipart("/comment") + .file(file) + .cookie(loginResult.getResponse().getCookies()) + .param("mid", String.valueOf(mid))).andExpect(status().isFound()); + mockMvc.perform(post("/comment") + .cookie(loginResult.getResponse().getCookies()) + .param("mid", String.valueOf(mid)) + .param("body", "yo")).andExpect(redirectedUrl(String.format("/%s/%d#%d", ugnichName, mid, 3))); + mockMvc.perform(post("/post2") + .cookie(loginResult.getResponse().getCookies()) + .param("body", String.format("D #%d/%d", mid, 3))) + .andExpect(status().isFound()); + assertThat(messagesService.getReplies(ugnich, mid).size(), equalTo(2)); + } + @Test + public void hashLoginShouldNotUseSession() throws Exception { + String hash = userService.getHashByUID(ugnich.getUid()); + MvcResult hashLoginResult = mockMvc.perform(get("/?show=my&hash=" + hash)) + .andExpect(status().isOk()) + .andExpect(model().attribute("visitor", hasProperty("authHash", equalTo(hash)))) + .andExpect(content().string(containsString(hash))) + .andReturn(); + Cookie rememberMeFromHash = hashLoginResult.getResponse().getCookie("juick-remember-me"); + MvcResult formLoginResult = mockMvc.perform(post("/login") + .param("username", ugnichName) + .param("password", ugnichPassword)) + .andExpect(status().is3xxRedirection()).andReturn(); + Cookie rememberMeFromForm = formLoginResult.getResponse().getCookie("juick-remember-me"); + mockMvc.perform(get("/?show=my").cookie(rememberMeFromForm)).andExpect(status().isOk()) + .andExpect(model().attribute("visitor", hasProperty("authHash", equalTo(hash)))) + .andExpect(content().string(containsString(hash))); + mockMvc.perform(get("/?show=my").cookie(rememberMeFromHash)).andExpect(status().isOk()) + .andExpect(model().attribute("visitor", hasProperty("authHash", equalTo(hash)))) + .andExpect(content().string(containsString(hash))); + } + @Test + public void nonExistentBlogShouldReturn404() throws Exception { + mockMvc.perform(get("/ololoe/")).andExpect(status().isNotFound()); + } + @Test + public void discussionsShouldBePageableByTimestamp() throws Exception { + String msgText = "Привет, я снова Угнич"; + int mid = messagesService.createMessage(ugnich.getUid(), msgText, null, null); + int midNew = messagesService.createMessage(ugnich.getUid(), "Я более новый Угнич", null, null); + MvcResult loginResult = mockMvc.perform(post("/login") + .param("username", freefdName) + .param("password", freefdPassword)) + .andExpect(status().is3xxRedirection()).andReturn(); + Cookie loginCookie = loginResult.getResponse().getCookie("juick-remember-me"); + webClient.setCookieManager(new CookieManager()); + webClient.getCookieManager().addCookie( + new com.gargoylesoftware.htmlunit.util.Cookie(loginCookie.getDomain(), + loginCookie.getName(), + loginCookie.getValue())); + String discussionsUrl = "http://localhost:8080/?show=discuss"; + HtmlPage discussions = webClient.getPage(discussionsUrl); + assertThat(discussions.querySelectorAll("article").size(), is(0)); + subscriptionService.subscribeMessage(messagesService.getMessage(mid), freefd); + discussions = (HtmlPage) discussions.refresh(); + assertThat(discussions.querySelectorAll("article").size(), is(1)); + subscriptionService.subscribeMessage(messagesService.getMessage(midNew), freefd); + discussions = (HtmlPage) discussions.refresh(); + assertThat(discussions.querySelectorAll("article").size(), is(2)); + assertThat(discussions.querySelectorAll("article").get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(midNew))); + messagesService.createReply(mid, 0, freefd, "I'm replied", null); + discussions = (HtmlPage) discussions.refresh(); + assertThat(discussions.querySelectorAll("article").size(), is(2)); + assertThat(discussions.querySelectorAll("article").get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(mid))); + Message msg = messagesService.getMessage(mid); + HtmlPage discussionsOld = webClient.getPage(discussionsUrl + "&to=" + msg.getUpdated().toEpochMilli()); + assertThat(discussionsOld.querySelectorAll("article").size(), is(1)); + assertThat(discussionsOld.querySelectorAll("article").get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(midNew))); + List newMids = IntStream.rangeClosed(1, 19).map(i -> messagesService.createMessage(ugnich.getUid(), String.valueOf(i), null, null)).boxed().collect(Collectors.toList()); + for (Integer m : newMids) { + subscriptionService.subscribeMessage(messagesService.getMessage(m), freefd); + } + discussions = (HtmlPage) discussions.refresh(); + assertThat(discussions.querySelectorAll("article").size(), is(20)); + assertThat(discussions.querySelectorAll("article") + .get(19).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(mid))); + messagesService.createReply(midNew, 0, freefd, "I'm replied", null); + discussions = (HtmlPage) discussions.refresh(); + assertThat(discussions.querySelectorAll("article") + .get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(midNew))); + Message old = messagesService.getMessage(newMids.get(0)); + discussionsOld = webClient.getPage(discussionsUrl + "&to=" + old.getUpdated().toEpochMilli()); + assertThat(discussionsOld.querySelectorAll("article").size(), is(1)); + assertThat(discussionsOld.querySelectorAll("article") + .get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(mid))); + } + @Test + public void redirectParamShouldCorrectlyRedirectLoggedUser() throws Exception { + MvcResult formLoginResult = mockMvc.perform(post("/login") + .param("username", ugnichName) + .param("password", ugnichPassword)) + .andExpect(status().isFound()).andReturn(); + Cookie rememberMeFromForm = formLoginResult.getResponse().getCookie("juick-remember-me"); + mockMvc.perform(get("/login").cookie(rememberMeFromForm)) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/")); + mockMvc.perform(get("/login?redirect=false").cookie(rememberMeFromForm)) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/login/success")); + } + @Test + public void anythingRedirects() throws Exception { + int mid = messagesService.createMessage(ugnich.getUid(), "yo", null, null); + mockMvc.perform(get(String.format("/%d", mid))) + .andExpect(status().isMovedPermanently()) + .andExpect(redirectedUrl(String.format("/%s/%d", ugnich.getName(), mid))); + } + @Test + public void appAssociationsTest() throws Exception { + mockMvc.perform((get("/.well-known/apple-app-site-association"))) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$.webcredentials.apps[0]", is(appId))); + } + @Test + public void notificationsTests() throws Exception { + MvcResult loginResult = mockMvc.perform(post("/login") + .param("username", freefdName) + .param("password", freefdPassword)) + .andExpect(status().is3xxRedirection()).andReturn(); + Cookie loginCookie = loginResult.getResponse().getCookie("juick-remember-me"); + webClient.setCookieManager(new CookieManager()); + webClient.getCookieManager().addCookie( + new com.gargoylesoftware.htmlunit.util.Cookie(loginCookie.getDomain(), + loginCookie.getName(), + loginCookie.getValue())); + int mid = messagesService.createMessage(ugnich.getUid(), "new test", null, null); + subscriptionService.subscribeMessage(messagesService.getMessage(mid), freefd); + int rid = messagesService.createReply(mid, 0, ugnich, "new reply", null); + HtmlPage discussionsPage = webClient.getPage("http://localhost:8080/?show=discuss"); + assertThat(discussionsPage.querySelectorAll("#global a .badge").size(), is(1)); + HtmlPage unreadThread = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); + assertThat(unreadThread.querySelectorAll("#global a .badge").size(), is(0)); + } + @Test + public void escapeSqlTests() { + String sql = String.format("SELECT * FROM table WHERE data='%s'", Utils.encodeSphinx("';-- DROP TABLE table")); + assertThat(sql, is("SELECT * FROM table WHERE data='\\';-- DROP TABLE table\'")); + } + @Test + public void bannedUserShouldBeShadowedFromRecommendationsList() throws IOException { + int ermineId = userService.createUser("ermine", "secret"); + int monstreekId = userService.createUser("monstreek", "secret"); + int pogoId = userService.createUser("pogo", "secret"); + int fmapId = userService.createUser("fmap", "secret"); + int mid = messagesService.createMessage(monstreekId, "KURWA", null, null); + assertThat(messagesService.recommendMessage(mid, ermineId), is(MessagesService.RecommendStatus.Added)); + assertThat(messagesService.recommendMessage(mid, fmapId), is(MessagesService.RecommendStatus.Added)); + assertThat(messagesService.recommendMessage(mid, pogoId), is(MessagesService.RecommendStatus.Added)); + assertThat(messagesService.getMessage(mid).getLikes(), is(3)); + assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid), Arrays.asList("fmap", "ermine", "pogo")), is(true)); + privacyQueriesService.blacklistUser(userService.getUserByName("monstreek"), userService.getUserByName("pogo")); + assertThat(messagesService.getMessage(mid).getLikes(), is(3)); + assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid), Arrays.asList("fmap", "ermine")), is(true)); + HtmlPage page = webClient.getPage(String.format("http://localhost:8080/monstreek/%d", mid)); + assertTrue(page.querySelector(".msg-recomms").getTextContent().contains("и еще 1")); + } +} -- cgit v1.2.3