diff --git a/STATUS.adoc b/STATUS.adoc index 04f0c94c..f25801ef 100644 --- a/STATUS.adoc +++ b/STATUS.adoc @@ -598,6 +598,31 @@ h|nativeTest | +5+^h|Graphql +h|Smoke Test +h|appTest +h|nativeAppTest +h|test +h|nativeTest +|graphql-webflux +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-native-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-native-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-native-test] + +|graphql-webflux-rsocket +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-native-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-native-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webflux-rsocket-native-test] + +|graphql-webmvc +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-native-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-native-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/graphql-webmvc-native-test] + + 5+^h|Integration h|Smoke Test h|appTest diff --git a/ci/smoke-tests.yml b/ci/smoke-tests.yml index 237d4395..ba53f11e 100644 --- a/ci/smoke-tests.yml +++ b/ci/smoke-tests.yml @@ -291,6 +291,17 @@ groups: - name: websocket-undertow app_test: true test: false + - name: graphql + smoke_tests: + - name: graphql-webflux + app_test: true + test: true + - name: graphql-webflux-rsocket + app_test: true + test: true + - name: graphql-webmvc + app_test: true + test: true - name: integration smoke_tests: - name: integration diff --git a/graphql/graphql-webflux-rsocket/README.adoc b/graphql/graphql-webflux-rsocket/README.adoc new file mode 100644 index 00000000..9c2266f9 --- /dev/null +++ b/graphql/graphql-webflux-rsocket/README.adoc @@ -0,0 +1 @@ +Tests if Spring for GraphQL with WebFlux over RSockets is working diff --git a/graphql/graphql-webflux-rsocket/build.gradle b/graphql/graphql-webflux-rsocket/build.gradle new file mode 100644 index 00000000..323a439f --- /dev/null +++ b/graphql/graphql-webflux-rsocket/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'java' + id 'org.springframework.boot' + id 'org.springframework.aot.smoke-test' + id 'org.graalvm.buildtools.native' +} + +dependencies { + implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-rsocket") + implementation("org.springframework.boot:spring-boot-starter-graphql") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.springframework.graphql:spring-graphql-test") + testImplementation("io.projectreactor:reactor-test") + + appTestImplementation(project(":aot-smoke-test-support")) + appTestImplementation("org.springframework.boot:spring-boot-starter-rsocket") + appTestImplementation("org.springframework.graphql:spring-graphql-test") + appTestImplementation("org.springframework.boot:spring-boot-starter-json") + appTestImplementation("io.projectreactor:reactor-test") +} + +aotSmokeTest { + webApplication = true +} diff --git a/graphql/graphql-webflux-rsocket/src/appTest/java/com/example/graphql/webflux/GraphQlApplicationAotTests.java b/graphql/graphql-webflux-rsocket/src/appTest/java/com/example/graphql/webflux/GraphQlApplicationAotTests.java new file mode 100644 index 00000000..cc83e5d8 --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/appTest/java/com/example/graphql/webflux/GraphQlApplicationAotTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import io.rsocket.transport.netty.client.TcpClientTransport; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.springframework.aot.smoketest.support.junit.ApplicationTest; +import org.springframework.graphql.client.RSocketGraphQlClient; + +@ApplicationTest +class GraphQlApplicationAotTests { + + @Test + void getProject() { + TcpClientTransport transport = TcpClientTransport.create(9090); + RSocketGraphQlClient graphQlClient = RSocketGraphQlClient.builder().clientTransport(transport).build(); + Mono projectName = graphQlClient.documentName("project").retrieve("project.name") + .toEntity(String.class); + StepVerifier.create(projectName).expectNext("Spring Framework").expectComplete().verify(); + } + +} diff --git a/graphql/graphql-webflux-rsocket/src/appTest/resources/graphql-documents/project.graphql b/graphql/graphql-webflux-rsocket/src/appTest/resources/graphql-documents/project.graphql new file mode 100644 index 00000000..d03ddbcc --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/appTest/resources/graphql-documents/project.graphql @@ -0,0 +1,5 @@ +{ + project(slug:"spring-framework") { + name + } +} \ No newline at end of file diff --git a/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/GraphQlApplication.java b/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/GraphQlApplication.java new file mode 100644 index 00000000..69e3806c --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/GraphQlApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GraphQlApplication { + + public static void main(String[] args) { + SpringApplication.run(GraphQlApplication.class, args); + } + +} diff --git a/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/Project.java b/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/Project.java new file mode 100644 index 00000000..cac9db21 --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/Project.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import java.util.Objects; + +public class Project { + + private String slug; + + private String name; + + public Project(String slug, String name) { + this.slug = slug; + this.name = name; + } + + public String getSlug() { + return this.slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Project project = (Project) o; + return this.slug.equals(project.slug); + } + + @Override + public int hashCode() { + return Objects.hash(this.slug); + } + +} diff --git a/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/ProjectController.java b/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/ProjectController.java new file mode 100644 index 00000000..036d25fc --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/main/java/com/example/graphql/webflux/ProjectController.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.stereotype.Controller; + +@Controller +public class ProjectController { + + private final List projects; + + public ProjectController() { + this.projects = Arrays.asList(new Project("spring-boot", "Spring Boot"), + new Project("spring-graphql", "Spring GraphQL"), new Project("spring-framework", "Spring Framework")); + } + + @QueryMapping + public Optional project(@Argument String slug) { + return this.projects.stream().filter((project) -> project.getSlug().equals(slug)).findFirst(); + } + +} \ No newline at end of file diff --git a/graphql/graphql-webflux-rsocket/src/main/resources/application.yml b/graphql/graphql-webflux-rsocket/src/main/resources/application.yml new file mode 100644 index 00000000..8d9955e5 --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/main/resources/application.yml @@ -0,0 +1,7 @@ +spring: + graphql: + rsocket: + mapping: graphql + rsocket: + server: + port: 9090 diff --git a/graphql/graphql-webflux-rsocket/src/main/resources/graphql/schema.graphqls b/graphql/graphql-webflux-rsocket/src/main/resources/graphql/schema.graphqls new file mode 100644 index 00000000..24f06b8f --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/main/resources/graphql/schema.graphqls @@ -0,0 +1,8 @@ +type Query { + project(slug: ID!): Project +} + +type Project { + slug: ID! + name: String! +} \ No newline at end of file diff --git a/graphql/graphql-webflux-rsocket/src/test/java/com/example/graphql/webflux/GraphQlTesterTests.java b/graphql/graphql-webflux-rsocket/src/test/java/com/example/graphql/webflux/GraphQlTesterTests.java new file mode 100644 index 00000000..19ce3de6 --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/test/java/com/example/graphql/webflux/GraphQlTesterTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureGraphQlTester; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.graphql.test.tester.GraphQlTester; + +@SpringBootTest +@AutoConfigureGraphQlTester +class GraphQlTesterTests { + + private static final String DOCUMENT = """ + { + project(slug:"spring-boot") { + name + } + } + """; + + @Autowired + private GraphQlTester graphQlTester; + + @Test + void getProject() { + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + +} diff --git a/graphql/graphql-webflux-rsocket/src/test/java/com/example/graphql/webflux/TcpTests.java b/graphql/graphql-webflux-rsocket/src/test/java/com/example/graphql/webflux/TcpTests.java new file mode 100644 index 00000000..14dfe6e9 --- /dev/null +++ b/graphql/graphql-webflux-rsocket/src/test/java/com/example/graphql/webflux/TcpTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import io.rsocket.transport.netty.client.TcpClientTransport; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureGraphQlTester; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.graphql.test.tester.RSocketGraphQlTester; + +@SpringBootTest +@AutoConfigureGraphQlTester +class TcpTests { + + private static final String DOCUMENT = """ + { + project(slug:"spring-boot") { + name + } + } + """; + + @Test + void getProject() { + TcpClientTransport transport = TcpClientTransport.create(9090); + RSocketGraphQlTester graphQlTester = RSocketGraphQlTester.builder().clientTransport(transport).build(); + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + +} \ No newline at end of file diff --git a/graphql/graphql-webflux/README.adoc b/graphql/graphql-webflux/README.adoc new file mode 100644 index 00000000..37c4f26f --- /dev/null +++ b/graphql/graphql-webflux/README.adoc @@ -0,0 +1 @@ +Tests if Spring for GraphQL with WebFlux over HTTP and WebSocket is working diff --git a/graphql/graphql-webflux/build.gradle b/graphql/graphql-webflux/build.gradle new file mode 100644 index 00000000..de1d6052 --- /dev/null +++ b/graphql/graphql-webflux/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' + id 'org.springframework.boot' + id 'org.springframework.aot.smoke-test' + id 'org.graalvm.buildtools.native' +} + +dependencies { + implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-websocket") + implementation("org.springframework.boot:spring-boot-starter-graphql") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.springframework.graphql:spring-graphql-test") + testImplementation("io.projectreactor:reactor-test") + + appTestImplementation(project(":aot-smoke-test-support")) + appTestImplementation("org.springframework.graphql:spring-graphql-test") + appTestImplementation("org.springframework.boot:spring-boot-starter-json") + appTestImplementation("io.projectreactor:reactor-test") +} + +aotSmokeTest { + webApplication = true +} diff --git a/graphql/graphql-webflux/src/appTest/java/com/example/graphql/webflux/GraphQlApplicationAotTests.java b/graphql/graphql-webflux/src/appTest/java/com/example/graphql/webflux/GraphQlApplicationAotTests.java new file mode 100644 index 00000000..bcf3c4de --- /dev/null +++ b/graphql/graphql-webflux/src/appTest/java/com/example/graphql/webflux/GraphQlApplicationAotTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import java.net.URI; + +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.springframework.aot.smoketest.support.junit.ApplicationTest; +import org.springframework.aot.smoketest.support.junit.ApplicationUrl; +import org.springframework.graphql.client.HttpGraphQlClient; +import org.springframework.graphql.client.WebSocketGraphQlClient; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; +import org.springframework.web.reactive.socket.client.WebSocketClient; + +@ApplicationTest +class GraphQlApplicationAotTests { + + @Test + void getProjectUsingHttp(@ApplicationUrl(scheme = ApplicationUrl.Scheme.HTTP) URI applicationUrl) { + WebClient webClient = WebClient.create(applicationUrl.toString() + "/graphql"); + HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient); + Mono projectName = graphQlClient.documentName("project").retrieve("project.name") + .toEntity(String.class); + StepVerifier.create(projectName).expectNext("Spring Framework").expectComplete().verify(); + } + + @Test + void getProjectUsingWebSocket(@ApplicationUrl(scheme = ApplicationUrl.Scheme.WEBSOCKET) URI applicationUrl) { + WebSocketClient webClient = new ReactorNettyWebSocketClient(); + WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient + .builder(applicationUrl.toString() + "/graphql", webClient).build(); + Mono projectName = graphQlClient.documentName("project").retrieve("project.name") + .toEntity(String.class); + StepVerifier.create(projectName).expectNext("Spring Framework").expectComplete().verify(); + } + +} diff --git a/graphql/graphql-webflux/src/appTest/resources/graphql-documents/project.graphql b/graphql/graphql-webflux/src/appTest/resources/graphql-documents/project.graphql new file mode 100644 index 00000000..d03ddbcc --- /dev/null +++ b/graphql/graphql-webflux/src/appTest/resources/graphql-documents/project.graphql @@ -0,0 +1,5 @@ +{ + project(slug:"spring-framework") { + name + } +} \ No newline at end of file diff --git a/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/GraphQlApplication.java b/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/GraphQlApplication.java new file mode 100644 index 00000000..69e3806c --- /dev/null +++ b/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/GraphQlApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GraphQlApplication { + + public static void main(String[] args) { + SpringApplication.run(GraphQlApplication.class, args); + } + +} diff --git a/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/Project.java b/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/Project.java new file mode 100644 index 00000000..cac9db21 --- /dev/null +++ b/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/Project.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import java.util.Objects; + +public class Project { + + private String slug; + + private String name; + + public Project(String slug, String name) { + this.slug = slug; + this.name = name; + } + + public String getSlug() { + return this.slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Project project = (Project) o; + return this.slug.equals(project.slug); + } + + @Override + public int hashCode() { + return Objects.hash(this.slug); + } + +} diff --git a/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/ProjectController.java b/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/ProjectController.java new file mode 100644 index 00000000..036d25fc --- /dev/null +++ b/graphql/graphql-webflux/src/main/java/com/example/graphql/webflux/ProjectController.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.stereotype.Controller; + +@Controller +public class ProjectController { + + private final List projects; + + public ProjectController() { + this.projects = Arrays.asList(new Project("spring-boot", "Spring Boot"), + new Project("spring-graphql", "Spring GraphQL"), new Project("spring-framework", "Spring Framework")); + } + + @QueryMapping + public Optional project(@Argument String slug) { + return this.projects.stream().filter((project) -> project.getSlug().equals(slug)).findFirst(); + } + +} \ No newline at end of file diff --git a/graphql/graphql-webflux/src/main/resources/application.yml b/graphql/graphql-webflux/src/main/resources/application.yml new file mode 100644 index 00000000..c6c3b9a6 --- /dev/null +++ b/graphql/graphql-webflux/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + graphql: + websocket: + path: /graphql \ No newline at end of file diff --git a/graphql/graphql-webflux/src/main/resources/graphql/schema.graphqls b/graphql/graphql-webflux/src/main/resources/graphql/schema.graphqls new file mode 100644 index 00000000..24f06b8f --- /dev/null +++ b/graphql/graphql-webflux/src/main/resources/graphql/schema.graphqls @@ -0,0 +1,8 @@ +type Query { + project(slug: ID!): Project +} + +type Project { + slug: ID! + name: String! +} \ No newline at end of file diff --git a/graphql/graphql-webflux/src/test/java/com/example/graphql/webflux/GraphQlTesterTests.java b/graphql/graphql-webflux/src/test/java/com/example/graphql/webflux/GraphQlTesterTests.java new file mode 100644 index 00000000..19ce3de6 --- /dev/null +++ b/graphql/graphql-webflux/src/test/java/com/example/graphql/webflux/GraphQlTesterTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureGraphQlTester; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.graphql.test.tester.GraphQlTester; + +@SpringBootTest +@AutoConfigureGraphQlTester +class GraphQlTesterTests { + + private static final String DOCUMENT = """ + { + project(slug:"spring-boot") { + name + } + } + """; + + @Autowired + private GraphQlTester graphQlTester; + + @Test + void getProject() { + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + +} diff --git a/graphql/graphql-webflux/src/test/java/com/example/graphql/webflux/RandomPortTests.java b/graphql/graphql-webflux/src/test/java/com/example/graphql/webflux/RandomPortTests.java new file mode 100644 index 00000000..4c1ff759 --- /dev/null +++ b/graphql/graphql-webflux/src/test/java/com/example/graphql/webflux/RandomPortTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webflux; + +import java.net.URI; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.graphql.test.tester.HttpGraphQlTester; +import org.springframework.graphql.test.tester.WebSocketGraphQlTester; +import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; +import org.springframework.web.reactive.socket.client.WebSocketClient; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(webEnvironment = RANDOM_PORT) +@AutoConfigureHttpGraphQlTester +class RandomPortTests { + + private static final String DOCUMENT = """ + { + project(slug:"spring-boot") { + name + } + } + """; + + @LocalServerPort + private int localPort; + + @Test + void getProjectUsingHttp(@Autowired HttpGraphQlTester graphQlTester) { + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + + @Test + void getProjectUsingWebSocket() { + WebSocketClient webClient = new ReactorNettyWebSocketClient(); + URI uri = URI.create("http://localhost:" + localPort + "/graphql"); + WebSocketGraphQlTester graphQlTester = WebSocketGraphQlTester.create(uri, webClient); + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + +} \ No newline at end of file diff --git a/graphql/graphql-webmvc/README.adoc b/graphql/graphql-webmvc/README.adoc new file mode 100644 index 00000000..705d7fdb --- /dev/null +++ b/graphql/graphql-webmvc/README.adoc @@ -0,0 +1 @@ +Tests if Spring for GraphQL with WebMVC is working diff --git a/graphql/graphql-webmvc/build.gradle b/graphql/graphql-webmvc/build.gradle new file mode 100644 index 00000000..d6120829 --- /dev/null +++ b/graphql/graphql-webmvc/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'java' + id 'org.springframework.boot' + id 'org.springframework.aot.smoke-test' + id 'org.graalvm.buildtools.native' +} + +dependencies { + implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-websocket") + implementation("org.springframework.boot:spring-boot-starter-graphql") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.springframework.boot:spring-boot-starter-webflux") + testImplementation("org.springframework.graphql:spring-graphql-test") + testImplementation("io.projectreactor:reactor-test") + + appTestImplementation(project(":aot-smoke-test-support")) + appTestImplementation("org.springframework.graphql:spring-graphql-test") + appTestImplementation("org.springframework.boot:spring-boot-starter-json") + appTestImplementation("io.projectreactor:reactor-test") +} + +aotSmokeTest { + webApplication = true +} diff --git a/graphql/graphql-webmvc/src/appTest/java/com/example/graphql/webmvc/GraphQlApplicationAotTests.java b/graphql/graphql-webmvc/src/appTest/java/com/example/graphql/webmvc/GraphQlApplicationAotTests.java new file mode 100644 index 00000000..d30b6107 --- /dev/null +++ b/graphql/graphql-webmvc/src/appTest/java/com/example/graphql/webmvc/GraphQlApplicationAotTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webmvc; + +import java.net.URI; + +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.springframework.aot.smoketest.support.junit.ApplicationTest; +import org.springframework.aot.smoketest.support.junit.ApplicationUrl; +import org.springframework.graphql.client.HttpGraphQlClient; +import org.springframework.graphql.client.WebSocketGraphQlClient; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; +import org.springframework.web.reactive.socket.client.WebSocketClient; + +@ApplicationTest +class GraphQlApplicationAotTests { + + @Test + void getProjectUsingHttp(@ApplicationUrl(scheme = ApplicationUrl.Scheme.HTTP) URI applicationUrl) { + WebClient webClient = WebClient.create(applicationUrl.toString() + "/graphql"); + HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient); + Mono projectName = graphQlClient.documentName("project").retrieve("project.name") + .toEntity(String.class); + StepVerifier.create(projectName).expectNext("Spring Framework").expectComplete().verify(); + } + + @Test + void getProjectUsingWebSocket(@ApplicationUrl(scheme = ApplicationUrl.Scheme.WEBSOCKET) URI applicationUrl) { + WebSocketClient webClient = new ReactorNettyWebSocketClient(); + WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient + .builder(applicationUrl.toString() + "/graphql", webClient).build(); + Mono projectName = graphQlClient.documentName("project").retrieve("project.name") + .toEntity(String.class); + StepVerifier.create(projectName).expectNext("Spring Framework").expectComplete().verify(); + } + +} diff --git a/graphql/graphql-webmvc/src/appTest/resources/graphql-documents/project.graphql b/graphql/graphql-webmvc/src/appTest/resources/graphql-documents/project.graphql new file mode 100644 index 00000000..d03ddbcc --- /dev/null +++ b/graphql/graphql-webmvc/src/appTest/resources/graphql-documents/project.graphql @@ -0,0 +1,5 @@ +{ + project(slug:"spring-framework") { + name + } +} \ No newline at end of file diff --git a/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/GraphQlApplication.java b/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/GraphQlApplication.java new file mode 100644 index 00000000..d1ec5d10 --- /dev/null +++ b/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/GraphQlApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webmvc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GraphQlApplication { + + public static void main(String[] args) { + SpringApplication.run(GraphQlApplication.class, args); + } + +} diff --git a/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/Project.java b/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/Project.java new file mode 100644 index 00000000..a254e5e9 --- /dev/null +++ b/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/Project.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webmvc; + +import java.util.Objects; + +public class Project { + + private String slug; + + private String name; + + public Project(String slug, String name) { + this.slug = slug; + this.name = name; + } + + public String getSlug() { + return this.slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Project project = (Project) o; + return this.slug.equals(project.slug); + } + + @Override + public int hashCode() { + return Objects.hash(this.slug); + } + +} diff --git a/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/ProjectController.java b/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/ProjectController.java new file mode 100644 index 00000000..596ec7ef --- /dev/null +++ b/graphql/graphql-webmvc/src/main/java/com/example/graphql/webmvc/ProjectController.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webmvc; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.stereotype.Controller; + +@Controller +public class ProjectController { + + private final List projects; + + public ProjectController() { + this.projects = Arrays.asList(new Project("spring-boot", "Spring Boot"), + new Project("spring-graphql", "Spring GraphQL"), new Project("spring-framework", "Spring Framework")); + } + + @QueryMapping + public Optional project(@Argument String slug) { + return this.projects.stream().filter((project) -> project.getSlug().equals(slug)).findFirst(); + } + +} \ No newline at end of file diff --git a/graphql/graphql-webmvc/src/main/resources/application.yml b/graphql/graphql-webmvc/src/main/resources/application.yml new file mode 100644 index 00000000..c6c3b9a6 --- /dev/null +++ b/graphql/graphql-webmvc/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + graphql: + websocket: + path: /graphql \ No newline at end of file diff --git a/graphql/graphql-webmvc/src/main/resources/graphql/schema.graphqls b/graphql/graphql-webmvc/src/main/resources/graphql/schema.graphqls new file mode 100644 index 00000000..24f06b8f --- /dev/null +++ b/graphql/graphql-webmvc/src/main/resources/graphql/schema.graphqls @@ -0,0 +1,8 @@ +type Query { + project(slug: ID!): Project +} + +type Project { + slug: ID! + name: String! +} \ No newline at end of file diff --git a/graphql/graphql-webmvc/src/test/java/com/example/graphql/webmvc/GraphQlTesterTests.java b/graphql/graphql-webmvc/src/test/java/com/example/graphql/webmvc/GraphQlTesterTests.java new file mode 100644 index 00000000..374309fd --- /dev/null +++ b/graphql/graphql-webmvc/src/test/java/com/example/graphql/webmvc/GraphQlTesterTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webmvc; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureGraphQlTester; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.graphql.test.tester.GraphQlTester; + +@SpringBootTest +@AutoConfigureGraphQlTester +class GraphQlTesterTests { + + private static final String DOCUMENT = """ + { + project(slug:"spring-boot") { + name + } + } + """; + + @Autowired + private GraphQlTester graphQlTester; + + @Test + void getProject() { + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + +} diff --git a/graphql/graphql-webmvc/src/test/java/com/example/graphql/webmvc/RandomPortTests.java b/graphql/graphql-webmvc/src/test/java/com/example/graphql/webmvc/RandomPortTests.java new file mode 100644 index 00000000..1e0486c1 --- /dev/null +++ b/graphql/graphql-webmvc/src/test/java/com/example/graphql/webmvc/RandomPortTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2022 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 + * + * https://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 com.example.graphql.webmvc; + +import java.net.URI; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.graphql.test.tester.HttpGraphQlTester; +import org.springframework.graphql.test.tester.WebSocketGraphQlTester; +import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; +import org.springframework.web.reactive.socket.client.WebSocketClient; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(webEnvironment = RANDOM_PORT) +@AutoConfigureHttpGraphQlTester +class RandomPortTests { + + private static final String DOCUMENT = """ + { + project(slug:"spring-boot") { + name + } + } + """; + + @LocalServerPort + private int localPort; + + @Test + void getProjectUsingHttp(@Autowired HttpGraphQlTester graphQlTester) { + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + + @Test + void getProjectUsingWebSocket() { + WebSocketClient webClient = new ReactorNettyWebSocketClient(); + URI uri = URI.create("http://localhost:" + localPort + "/graphql"); + WebSocketGraphQlTester graphQlTester = WebSocketGraphQlTester.create(uri, webClient); + graphQlTester.document(DOCUMENT).execute().path("project.name").entity(String.class).isEqualTo("Spring Boot"); + } + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 19085539..77d171a9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,7 +27,7 @@ rootProject.name="spring-aot-smoke-tests" include "aot-smoke-test-support" include "aot-smoke-test-third-party-hints" -["batch", "boot", "cloud", "data", "framework", "integration", "security", "session"].each { group -> +["batch", "boot", "cloud", "data", "framework", "graphql", "integration", "security", "session"].each { group -> file(group).eachDirMatch(~/[a-z].*/) { smokeTest -> include "$group:${smokeTest.name}" }