-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GraphQL entity restore endpoint. Functional test added jmix-projects/…
- Loading branch information
Showing
9 changed files
with
570 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,62 @@ | ||
archivesBaseName = 'jmix-datatools-graphql' | ||
|
||
apply plugin: 'groovy' | ||
|
||
dependencies { | ||
compileOnly 'io.jmix.datatools:jmix-datatools' | ||
compileOnly 'io.jmix.graphql:jmix-graphql' | ||
testImplementation 'io.jmix.graphql:jmix-graphql-starter' | ||
|
||
|
||
testImplementation 'org.spockframework:spock-core' | ||
testImplementation 'org.spockframework:spock-spring' | ||
testImplementation('org.springframework.boot:spring-boot-starter-test') | ||
{ | ||
exclude module: "spring-boot-starter-logging" | ||
} | ||
|
||
testImplementation('com.graphql-java-kickstart:graphql-spring-boot-starter-test:11.0.0') | ||
{ | ||
// todo configure logger correctly | ||
exclude module: "spring-boot-starter-logging" | ||
} | ||
testImplementation 'io.jmix.core:jmix-core-starter' | ||
testImplementation 'io.jmix.data:jmix-data' | ||
testImplementation 'io.jmix.data:jmix-eclipselink-starter' | ||
testImplementation 'io.jmix.security:jmix-security-starter' | ||
testImplementation 'io.jmix.security:jmix-security-data-starter' | ||
testImplementation 'io.jmix.security:jmix-security-oauth2-starter' | ||
|
||
testImplementation 'com.google.code.gson:gson:2.8.6' | ||
|
||
testImplementation 'org.springframework:spring-test' | ||
testImplementation 'org.springframework.security:spring-security-test' | ||
|
||
testImplementation 'org.apache.commons:commons-dbcp2' | ||
|
||
testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.0.3' | ||
testImplementation 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.2' | ||
|
||
testImplementation 'io.rest-assured:rest-assured' | ||
|
||
testRuntimeOnly 'org.slf4j:slf4j-simple' | ||
testRuntimeOnly 'org.hsqldb:hsqldb' | ||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' | ||
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' | ||
|
||
|
||
testImplementation 'io.jmix.datatools:jmix-datatools-starter' | ||
|
||
testRuntimeOnly 'org.slf4j:slf4j-simple' | ||
testRuntimeOnly 'org.hsqldb:hsqldb' | ||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' | ||
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' | ||
|
||
} | ||
|
||
test { | ||
useJUnitPlatform() | ||
testLogging { | ||
events "passed", "skipped", "failed" | ||
} | ||
} |
125 changes: 125 additions & 0 deletions
125
jmix-datatools-graphql/src/test/groovy/io/jmix/datatools/graphql/AbstractGraphQLTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* | ||
* Copyright 2021 Haulmont. | ||
* | ||
* 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 io.jmix.datatools.graphql | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import com.fasterxml.jackson.databind.node.ObjectNode | ||
import com.google.gson.JsonArray | ||
import com.google.gson.JsonObject | ||
import com.google.gson.JsonParser | ||
import com.graphql.spring.boot.test.GraphQLResponse | ||
import com.graphql.spring.boot.test.GraphQLTestTemplate | ||
import io.jmix.core.security.InMemoryUserRepository | ||
import io.jmix.security.authentication.RoleGrantedAuthority | ||
import io.jmix.security.role.ResourceRoleRepository | ||
import org.springframework.beans.factory.annotation.Autowired | ||
import org.springframework.boot.test.context.SpringBootTest | ||
import org.springframework.boot.web.server.LocalServerPort | ||
import org.springframework.http.HttpHeaders | ||
import org.springframework.security.core.userdetails.User | ||
import org.springframework.security.core.userdetails.UserDetails | ||
import org.springframework.transaction.PlatformTransactionManager | ||
import org.springframework.transaction.TransactionDefinition | ||
import org.springframework.transaction.support.TransactionTemplate | ||
import spock.lang.Specification | ||
import test_support.App | ||
import test_support.RestTestUtils | ||
|
||
@SpringBootTest(classes = App, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | ||
class AbstractGraphQLTest extends Specification { | ||
|
||
@LocalServerPort | ||
int port | ||
@Autowired | ||
GraphQLTestTemplate graphQLTestTemplate | ||
@Autowired | ||
ResourceRoleRepository resourceRoleRepository | ||
@Autowired | ||
InMemoryUserRepository userRepository | ||
|
||
protected TransactionTemplate transaction | ||
protected String adminToken | ||
protected UserDetails admin | ||
|
||
void setup() { | ||
admin = User.builder() | ||
.username("admin") | ||
.password("{noop}admin") | ||
.authorities(RoleGrantedAuthority.ofResourceRole(resourceRoleRepository.getRoleByCode("system-full-access"))) | ||
.build() | ||
userRepository.addUser(admin) | ||
|
||
adminToken = RestTestUtils.getAuthToken("admin", "admin", port) | ||
} | ||
|
||
@Autowired | ||
protected void setTransactionManager(PlatformTransactionManager transactionManager) { | ||
transaction = new TransactionTemplate(transactionManager) | ||
transaction.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW) | ||
} | ||
|
||
protected GraphQLResponse query(String queryFilePath) { | ||
return graphQLTestTemplate | ||
.withBearerAuth(adminToken) | ||
.postForResource("io/jmix/datatools/graphql/" + queryFilePath) | ||
} | ||
|
||
protected GraphQLResponse query(String queryFilePath, HttpHeaders httpHeaders) { | ||
return graphQLTestTemplate | ||
.withHeaders(httpHeaders) | ||
.withBearerAuth(adminToken) | ||
.postForResource("io/jmix/datatools/graphql/" + queryFilePath) | ||
} | ||
|
||
protected GraphQLResponse query(String queryFilePath, ObjectNode variables) { | ||
return query(queryFilePath, variables, adminToken) | ||
} | ||
|
||
protected GraphQLResponse query(String queryFilePath, String variables) { | ||
return query(queryFilePath, asObjectNode(variables), adminToken) | ||
} | ||
|
||
protected GraphQLResponse query(String queryFilePath, ObjectNode variables, String token) { | ||
return graphQLTestTemplate | ||
.withBearerAuth(token) | ||
.perform("graphql/io/jmix/graphql/" + queryFilePath, variables) | ||
} | ||
|
||
static ObjectNode asObjectNode(String str) { | ||
return new ObjectMapper().readValue(str, ObjectNode.class) | ||
} | ||
|
||
static String getBody(GraphQLResponse response) { | ||
return response.rawResponse.body | ||
} | ||
|
||
static JsonObject getExtensions(JsonObject error) { | ||
error.getAsJsonObject("extensions").getAsJsonObject() | ||
} | ||
|
||
static String getMessage(JsonObject jsonObject) { | ||
jsonObject.get("message").getAsString() | ||
} | ||
|
||
static String getPath(JsonObject jsonObject) { | ||
jsonObject.get("path").getAsString() | ||
} | ||
|
||
static JsonArray getErrors(GraphQLResponse response) { | ||
JsonParser.parseString(response.rawResponse.body).getAsJsonArray("errors") | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
jmix-datatools-graphql/src/test/groovy/io/jmix/datatools/graphql/DatatoolsGraphqlTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package io.jmix.datatools.graphql | ||
|
||
import com.graphql.spring.boot.test.GraphQLResponse | ||
import io.jmix.core.UnconstrainedDataManager | ||
import org.springframework.beans.factory.annotation.Autowired | ||
import test_support.entity.Customer | ||
|
||
class DatatoolsGraphqlTest extends AbstractGraphQLTest { | ||
private static final UUID ID = UUID.fromString("bb7b5923-5b88-4dd7-aad9-9d2f735009dd") | ||
|
||
@Autowired | ||
private UnconstrainedDataManager dataManager | ||
|
||
def "Entity restore endpoint works"() { | ||
when: | ||
Customer customer = dataManager.create(Customer) | ||
customer.id = ID | ||
customer.name = "Ivan" | ||
customer = dataManager.save(customer) | ||
dataManager.remove(customer) | ||
|
||
GraphQLResponse response = query("test/restoreEntities.graphql") | ||
|
||
Optional<Customer> loaded = dataManager.load(Customer).id(customer.id).optional() | ||
|
||
then: | ||
response.getRawResponse().getBody() == '{"data":{"restoreEntities":1}}' | ||
loaded.isPresent() | ||
|
||
} | ||
|
||
} | ||
|
||
|
81 changes: 81 additions & 0 deletions
81
jmix-datatools-graphql/src/test/java/test_support/App.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright 2021 Haulmont. | ||
* | ||
* 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 test_support; | ||
|
||
import io.jmix.core.JmixModules; | ||
import io.jmix.core.Resources; | ||
import io.jmix.core.Stores; | ||
import io.jmix.core.security.InMemoryUserRepository; | ||
import io.jmix.core.security.UserRepository; | ||
import io.jmix.data.impl.JmixEntityManagerFactoryBean; | ||
import io.jmix.data.persistence.DbmsSpecifics; | ||
import io.jmix.security.StandardSecurityConfiguration; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseDataSource; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Primary; | ||
import org.springframework.context.annotation.PropertySource; | ||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; | ||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; | ||
import org.springframework.orm.jpa.JpaVendorAdapter; | ||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; | ||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||
|
||
import javax.sql.DataSource; | ||
|
||
|
||
@SpringBootApplication(scanBasePackages = "io.jmix.datatools.graphql") | ||
@PropertySource("classpath:/test_support/test-app.properties") | ||
public class App { | ||
|
||
public static void main(String[] args) { | ||
SpringApplication.run(App.class, args); | ||
} | ||
|
||
@Bean | ||
@Primary | ||
@LiquibaseDataSource | ||
DataSource dataSource() { | ||
return new EmbeddedDatabaseBuilder() | ||
.generateUniqueName(true) | ||
.setType(EmbeddedDatabaseType.HSQL) | ||
.build(); | ||
} | ||
|
||
@Bean | ||
@Primary | ||
UserRepository userRepository() { | ||
return new InMemoryUserRepository(); | ||
} | ||
|
||
|
||
@Bean | ||
@Primary | ||
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, | ||
DbmsSpecifics dbmsSpecifics, | ||
JmixModules jmixModules, | ||
JpaVendorAdapter jpaVendorAdapter, | ||
Resources resources) { | ||
return new JmixEntityManagerFactoryBean(Stores.MAIN, dataSource, jpaVendorAdapter, dbmsSpecifics, jmixModules, resources); | ||
} | ||
|
||
|
||
@EnableWebSecurity | ||
static class TestSecurityConfiguration extends StandardSecurityConfiguration { | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
jmix-datatools-graphql/src/test/java/test_support/RestTestUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Copyright 2019 Haulmont. | ||
* | ||
* 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 test_support; | ||
|
||
import com.jayway.jsonpath.JsonPath; | ||
import com.jayway.jsonpath.ReadContext; | ||
import org.apache.http.HttpEntity; | ||
import org.apache.http.NameValuePair; | ||
import org.apache.http.client.entity.UrlEncodedFormEntity; | ||
import org.apache.http.client.methods.CloseableHttpResponse; | ||
import org.apache.http.client.methods.HttpPost; | ||
import org.apache.http.impl.client.CloseableHttpClient; | ||
import org.apache.http.impl.client.HttpClients; | ||
import org.apache.http.message.BasicNameValuePair; | ||
import org.apache.http.util.EntityUtils; | ||
|
||
import java.io.IOException; | ||
import java.util.*; | ||
|
||
import static org.apache.http.HttpStatus.SC_OK; | ||
|
||
/** | ||
* Utility class for the REST API functional tests | ||
*/ | ||
public class RestTestUtils { | ||
|
||
public static final String CLIENT_ID = "client"; | ||
public static final String CLIENT_SECRET = "secret"; | ||
|
||
public static String getAuthToken(String login, String password, int port) throws IOException { | ||
return getAuthToken("http://localhost:" + port, login, password, new HashMap<>()); | ||
} | ||
|
||
public static String getAuthToken(String baseUrl, String login, String password, Map<String, String> headers) throws IOException { | ||
String uri = baseUrl + "/oauth/token"; | ||
|
||
CloseableHttpClient httpClient = HttpClients.createDefault(); | ||
String encoding = Base64.getEncoder().encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes()); | ||
HttpPost httpPost = new HttpPost(uri); | ||
httpPost.setHeader("Authorization", "Basic " + encoding); | ||
for (Map.Entry<String, String> entry : headers.entrySet()) { | ||
httpPost.setHeader(entry.getKey(), entry.getValue()); | ||
} | ||
|
||
List<NameValuePair> urlParameters = new ArrayList<NameValuePair>(); | ||
urlParameters.add(new BasicNameValuePair("grant_type", "password")); | ||
urlParameters.add(new BasicNameValuePair("username", login)); | ||
urlParameters.add(new BasicNameValuePair("password", password)); | ||
|
||
httpPost.setEntity(new UrlEncodedFormEntity(urlParameters)); | ||
|
||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) { | ||
int statusCode = response.getStatusLine().getStatusCode(); | ||
if (statusCode != SC_OK) { | ||
throw new AuthException(statusCode); | ||
} | ||
ReadContext ctx = parseResponse(response); | ||
return ctx.read("$.access_token"); | ||
} | ||
} | ||
|
||
public static ReadContext parseResponse(CloseableHttpResponse response) throws IOException { | ||
HttpEntity entity = response.getEntity(); | ||
String s = EntityUtils.toString(entity); | ||
return JsonPath.parse(s); | ||
} | ||
|
||
|
||
public static class AuthException extends RuntimeException { | ||
|
||
private int statusCode; | ||
|
||
public AuthException(int statusCode) { | ||
this.statusCode = statusCode; | ||
} | ||
} | ||
} |
Oops, something went wrong.