/* * Copyright (c) 2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.illyasviel.elide.spring.boot; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableMap; import java.util.Map; import org.illyasviel.elide.spring.boot.repository.AccountRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; /** * GraphQLTest. * * @author olOwOlo */ @Transactional @RunWith(SpringRunner.class) @SpringBootTest(classes = TApplication.class) public class GraphQLTest { private final static ObjectMapper objectMapper = new ObjectMapper(); private MockMvc mockMvc; @Autowired private WebApplicationContext wac; @Autowired private AccountRepository accountRepository; @Before public void before() { this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void testCreate() throws Exception { graphQLQuery( "mutation createAccount($name: String, $pw: String) { account(op: UPSERT, data: { username: $name, password: $pw }) { edges { node { id username password } } } }", ImmutableMap.of("name", "alice", "pw", "123")) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.account.edges[0].node.username").value("alice")) .andExpect(jsonPath("$.data.account.edges[0].node.password").value("123")); } @Sql(statements = "insert into account(id, username, password) values (233, 'alice', '123')") @Test public void testRead() throws Exception { graphQLQuery("query { account { edges { node { id username password } } } }") .andExpect(status().isOk()) .andExpect(jsonPath("$.data.account.edges.length()").value(1)) .andExpect(jsonPath("$.data.account.edges[0].node.id").value("233")) .andExpect(jsonPath("$.data.account.edges[0].node.username").value("alice")) .andExpect(jsonPath("$.data.account.edges[0].node.password").value("123")); } @Sql(statements = { "insert into account(id, username, password) values (233, 'alice', '123')", "delete from book", "insert into book(id, unique_number) values (666, 1)" }) @Test public void testReadByArray() throws Exception { String accountQuery = toJsonQuery("query { account { edges { node { id username password } } } }", null); String bookQuery = toJsonQuery("query { book { edges { node { id uniqueNumber } } } }", null); mockMvc.perform(post("/api/graphql") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content("[" + accountQuery + "," + bookQuery + "]")) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.length()").value(2)) .andExpect(jsonPath("$[0].data.account.edges[0].node.id").value("233")) .andExpect(jsonPath("$[1].data.book.edges[0].node.id").value("666")) .andExpect(jsonPath("$[1].data.book.edges[0].node.uniqueNumber").value(1)); } @Sql(statements = "insert into account(id, username, password) values (233, 'alice', '123')") @Test public void testUpdate() throws Exception { graphQLQuery("mutation { account(op: UPDATE, data: { id: \"233\", username: \"bob\" }) { edges { node { id username } } } }") .andExpect(status().isOk()) .andExpect(jsonPath("$.data.account.edges.length()").value(1)) .andExpect(jsonPath("$.data.account.edges[0].node.id").value("233")) .andExpect(jsonPath("$.data.account.edges[0].node.username").value("bob")); } @Sql(statements = "insert into account(id, username, password) values (1, 'alice', '123'), (2, 'bob', '123'), (3, 'eve', '123')") @Test public void testDelete() throws Exception { graphQLQuery("mutation { account(op: DELETE, ids: [\"1\", \"2\"]) { edges { node { id username } } } }") .andExpect(status().isOk()); assertThat(accountRepository.findAll().size()).isEqualTo(1); } @Test public void testInvalidJson() throws Exception { mockMvc.perform(post("/api/graphql") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content("Invalid Json")) .andExpect(status().isBadRequest()); } @Test public void testInvalidGraphQL() throws Exception { graphQLQuery("mutation create($some, $pw: String) { account() { } }") .andExpect(status().isOk()) .andExpect(jsonPath("$.errors").exists()) .andExpect(jsonPath("$.errors[0].message").value("Invalid Syntax")); } @Sql(statements = { "delete from book", "insert into book(id, unique_number) values (666, 1)" }) @Test public void testPersistenceException() throws Exception { graphQLQuery("mutation { book(op: UPSERT, data: { uniqueNumber: 1 }) { edges { node { id uniqueNumber } } } }") .andExpect(jsonPath("$.errors.length()").value(1)); } private ResultActions graphQLQuery(String query) throws Exception { return graphQLQuery(query, null); } private ResultActions graphQLQuery(String query, Map<String, Object> variables) throws Exception { return mockMvc.perform(post("/api/graphql") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(toJsonQuery(query, variables))); } private String toJsonQuery(String query, Map<String, Object> variables) throws JsonProcessingException { return objectMapper.writeValueAsString(toJsonNode(query, variables)); } private JsonNode toJsonNode(String query, Map<String, Object> variables) { ObjectNode graphQLNode = JsonNodeFactory.instance.objectNode(); graphQLNode.put("query", query); if (variables != null) { graphQLNode.set("variables", objectMapper.valueToTree(variables)); } return graphQLNode; } }