From cc877e4812b6cd99f4410e33adf7de1dac87ea60 Mon Sep 17 00:00:00 2001 From: grabdoc Date: Tue, 9 Jan 2024 01:14:07 -0600 Subject: [PATCH] #106 - rest docs added, restassured removed, will use webmvcmock --- FILTER.md | 274 ------------------ pom.xml | 51 +++- .../homihq/db2rest/BaseIntegrationTest.java | 36 +++ .../db2rest/Db2restApplicationTests.java | 13 - .../db2rest/MySQLBaseIntegrationTest.java | 28 ++ .../PostgreSQLBaseIntegrationTest.java | 30 ++ .../db2rest/rest/PgReadControllerTest.java | 29 ++ .../db2rest/rest/ReadControllerTest.java | 70 ----- 8 files changed, 165 insertions(+), 366 deletions(-) delete mode 100644 FILTER.md create mode 100644 src/test/java/com/homihq/db2rest/BaseIntegrationTest.java delete mode 100644 src/test/java/com/homihq/db2rest/Db2restApplicationTests.java create mode 100644 src/test/java/com/homihq/db2rest/MySQLBaseIntegrationTest.java create mode 100644 src/test/java/com/homihq/db2rest/PostgreSQLBaseIntegrationTest.java create mode 100644 src/test/java/com/homihq/db2rest/rest/PgReadControllerTest.java delete mode 100644 src/test/java/com/homihq/db2rest/rest/ReadControllerTest.java diff --git a/FILTER.md b/FILTER.md deleted file mode 100644 index efabe536..00000000 --- a/FILTER.md +++ /dev/null @@ -1,274 +0,0 @@ -# Filter Design V2 (!!!NOT USED!!!) - - -## Introduction - -Filtering is the process of limiting a collection resource by using a per-request dynamic criteria definition.Filtering enables efficient traversal of large collections. -Filtering can also be backed with pagination where each page contains a subset of items found in the complete collection. - -To filter in a query, include the parameter q=QueryObject, where QueryObject is a JSON object that represents the custom selection, pagination and sorting to be applied to the resource. - -For example, assume the following resource: - -```ruby -https://db2rest.com/actors -``` - -The following query includes a filter that restricts actors with first_name column to "Robert" - -```ruby -https://db2rest.com/actors?q={"first_name":"Robert"} -``` - -## QueryObject Grammer - -**EQUALS operator ($eq)** - -(Implicit and explicit equality supported.) - -Implicit (Support String and Dates too) - -```ruby -https://db2rest.com/actors?q={"year": 1999} -``` - -Explicit - -```ruby -https://db2rest.com/actors?q={"year": {"$eq": 1000} } -``` - -Strings - -```ruby -https://db2rest.com/actors?q={"first_name": {"$eq": "Robert"} } -``` - -Dates - -```ruby -https://db2rest.com/actors?q={"date_of_birth": {"$date": "1981-11-17T08:00:00Z"} } -``` - - -**NOT EQUALS operator ($ne)** - -Number - -```ruby -{"budget": {"$ne": 1000000}} -``` - -String - -```ruby -{"last_name": {"$ne":"De Niro"}} -``` - -Dates - -```ruby -{"date_of_birth": {"$ne": {"$date":"1981-11-17T08:00:00Z"}}} -``` - - -**LESS THAN operator ($lt)** -(Supports dates and numbers only) - -Numbers - -```ruby -{"budget": {"$lt": 100000000} } -``` - -Dates - -```ruby -{"date_of_release": {"$lt": {"$date":"1999-12-17T08:00:00Z"}}} -``` - -**LESS THAN OR EQUALS operator ($lte)** -(Supports dates and numbers only) - -Numbers - -```ruby -{"budget": {"$lte": 100000000}} -``` - -Dates - -```ruby -{ "date_of_birth": {"$lte": {"$date":"1999-12-17T08:00:00Z"}} } -``` - -**GREATER THAN operator ($gt)** -(Supports dates and numbers only) - -Numbers - -```ruby -{ "budget": {"$gt": 10000} } -``` - -Dates - -```ruby -{ "date_of_birth": {"$gt": {"$date":"1999-12-17T08:00:00Z"}} } -``` - -**GREATER THAN OR EQUALS operator ($gte)** -(Supports dates and numbers only) - -Numbers - -```ruby -{"budget": {"$gte": 10000}} -``` - -Dates - -```ruby -{"date_of_birth": {"$gte": {"$date":"1999-12-17T08:00:00Z"}} } -``` - -**In string operator ($instr)** -(Supports strings only) - -```ruby -{"first_name": {"$instr":"MC"}} -``` - -Not in string operator ($ninstr) -(Supports strings only) - -```ruby -{"first_name": {"$ninstr":"MC"}} -``` - - -#### LIKE operator ($like) -(Supports strings. Eescape character not supported to try to match expressions with _ or % characters.) - -```ruby -{"first_name": {"$like":"AX%"}} -``` - -#### BETWEEN operator ($between) -(Supports string, dates, and numbers) - -Numbers - -```ruby -{"budget": {"$between": [1000,2000]}} -``` -Dates - -```ruby -{"release_date": {"$between": [{"$date":"1989-12-17T08:00:00Z"},{"$date":"1999-12-17T08:00:00Z"}]}} -``` - -Strings - -```ruby -{"first_name": {"$between": ["A","C"]}} -``` - -**Null Ranges ($lte equivalent)** -(Supported by numbers and dates only) - -```ruby -{"budget": {"$between": [null,2000]}} -``` - -Null Ranges ($gte equivalent) -(Supported by numbers and dates only) - -```ruby -{"budget": {"$between": [1000,null]}} -``` - -#### NULL operator ($null) - -```ruby -{"first_name": {"$null": null}} -``` - -#### NOT NULL operator ($notnull) - -```ruby -{"first_name": {"$notnull": null}} -``` - - -#### AND operator ($and) -(Supports all operators, including $and and $or) - -Column context delegation -(Operators inside $and will use the closest context defined in the JSON tree.) - -```ruby -{"budget": {"$and": [{"$gt": 1000},{"$lt":4000}]}} -``` - -Column context override -(Example: salary greater than 1000 and name like S%) - -```ruby -{ -"SALARY": {"$and": [{"$gt": 1000},{"ENAME": {"$like":"S%"}} ] } -} -``` - -Implicit and in columns - -```ruby -{"budget": [{"$gt": 1000},{"$lt":4000}]} -``` - -High order AND -(All first columns and or high order operators -- $and and $ors -- defined at the first level of the JSON will be joined and an implicit AND) -(Example: Salary greater than 1000 and name starts with S or T) - -```ruby -{ "budget": {"$gt": 1000},"first_name": {"$or": [{"$like":"S%"}, {"$like":"T%"}]}} -``` - -Invalid expression (operators $lt and $gt lack column context) - -```ruby -{"$and": [{"$lt": 5000},{"$gt": 1000}]} -``` - -Valid alternatives for the previous invalid expression - -```ruby -{"$and": [{"budget": {"$lt": 5000}}, {"budget": {"$gt": 1000}}]} -``` - -```ruby -{"budget": [{"$lt": 5000},{"$gt": 1000}]} -``` - -```ruby -{"budget": {"$and": [{"$lt": 5000},{"$gt": 1000}]}} -``` - -#### OR operator ($or) -(Supports all operators including $and and $or) - -Column context delegation -(Operators inside $or will use the closest context defined in the JSON tree) - -```ruby -{"budget": {"$or": [{"$eq":"SMITH"},{"$eq":"KING"}]} } -``` - -Column context override -(Example: name starts with S or salary greater than 1000) - -```ruby -{ -"budget": {"$or": [{"$gt": 1000},{"last_name": {"$like":"S%"}} ] } -} -``` diff --git a/pom.xml b/pom.xml index 91f3c17f..01bffdda 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ db2rest 21 + 3.0.1 @@ -159,13 +160,7 @@ spring-boot-starter-test test - + org.springframework.boot spring-boot-testcontainers @@ -185,8 +180,21 @@ - io.rest-assured - rest-assured + org.testcontainers + mysql + test + + + + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + + + org.springframework.boot + spring-boot-test-autoconfigure test @@ -195,6 +203,31 @@ db2rest + + org.asciidoctor + asciidoctor-maven-plugin + 2.2.4 + + + generate-docs + prepare-package + + process-asciidoc + + + html + book + + + + + + org.springframework.restdocs + spring-restdocs-asciidoctor + ${spring-restdocs.version} + + + org.springframework.boot spring-boot-maven-plugin diff --git a/src/test/java/com/homihq/db2rest/BaseIntegrationTest.java b/src/test/java/com/homihq/db2rest/BaseIntegrationTest.java new file mode 100644 index 00000000..40496ae5 --- /dev/null +++ b/src/test/java/com/homihq/db2rest/BaseIntegrationTest.java @@ -0,0 +1,36 @@ +package com.homihq.db2rest; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +@ActiveProfiles("it") +@ExtendWith({ RestDocumentationExtension.class}) +public abstract class BaseIntegrationTest { + + @Autowired + public MockMvc mockMvc; + + @BeforeEach + void setUp(WebApplicationContext webApplicationContext, + RestDocumentationContextProvider restDocumentation) { + mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + + +} diff --git a/src/test/java/com/homihq/db2rest/Db2restApplicationTests.java b/src/test/java/com/homihq/db2rest/Db2restApplicationTests.java deleted file mode 100644 index c44b5919..00000000 --- a/src/test/java/com/homihq/db2rest/Db2restApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.homihq.db2rest; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -//@SpringBootTest -class Db2restApplicationTests { - - //@Test - void contextLoads() { - } - -} diff --git a/src/test/java/com/homihq/db2rest/MySQLBaseIntegrationTest.java b/src/test/java/com/homihq/db2rest/MySQLBaseIntegrationTest.java new file mode 100644 index 00000000..ab1d5a3c --- /dev/null +++ b/src/test/java/com/homihq/db2rest/MySQLBaseIntegrationTest.java @@ -0,0 +1,28 @@ +package com.homihq.db2rest; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.testcontainers.containers.MySQLContainer; + +public class MySQLBaseIntegrationTest extends BaseIntegrationTest{ + + @ServiceConnection + private static final MySQLContainer mySQLContainer = new MySQLContainer("mysql:8.2"); + + static { + mySQLContainer.withUrlParam("serverTimezone", "UTC") + .withReuse(true) + .start(); + } + + @BeforeAll + static void beforeAll() { + mySQLContainer.start(); + } + + @AfterAll + static void afterAll() { + mySQLContainer.stop(); + } +} diff --git a/src/test/java/com/homihq/db2rest/PostgreSQLBaseIntegrationTest.java b/src/test/java/com/homihq/db2rest/PostgreSQLBaseIntegrationTest.java new file mode 100644 index 00000000..1dab1b5d --- /dev/null +++ b/src/test/java/com/homihq/db2rest/PostgreSQLBaseIntegrationTest.java @@ -0,0 +1,30 @@ +package com.homihq.db2rest; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.containers.PostgreSQLContainer; + +public class PostgreSQLBaseIntegrationTest extends BaseIntegrationTest{ + + @ServiceConnection + private static final PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:15-alpine"); + + static { + postgreSQLContainer.withUsername("postgres") + .withPassword("postgres") + .withInitScript("pg/postgres-sakila-schema.sql") // inside src/test/resources + .withDatabaseName("postgres"); + } + + @BeforeAll + static void beforeAll() { + postgreSQLContainer.start(); + } + + @AfterAll + static void afterAll() { + postgreSQLContainer.stop(); + } +} diff --git a/src/test/java/com/homihq/db2rest/rest/PgReadControllerTest.java b/src/test/java/com/homihq/db2rest/rest/PgReadControllerTest.java new file mode 100644 index 00000000..dfe06916 --- /dev/null +++ b/src/test/java/com/homihq/db2rest/rest/PgReadControllerTest.java @@ -0,0 +1,29 @@ +package com.homihq.db2rest.rest; + +import com.homihq.db2rest.PostgreSQLBaseIntegrationTest; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; + +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.request.RequestDocumentation.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +class PgReadControllerTest extends PostgreSQLBaseIntegrationTest { + + @Test + @DisplayName("Get all fields.") + void findAllFilms() throws Exception { + + + mockMvc.perform(get("/films") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andDo(document("get-all-films")); + } +} diff --git a/src/test/java/com/homihq/db2rest/rest/ReadControllerTest.java b/src/test/java/com/homihq/db2rest/rest/ReadControllerTest.java deleted file mode 100644 index 4c46193a..00000000 --- a/src/test/java/com/homihq/db2rest/rest/ReadControllerTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.homihq.db2rest.rest; - -import io.restassured.RestAssured; -import io.restassured.http.ContentType; -import io.restassured.parsing.Parser; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.boot.testcontainers.service.connection.ServiceConnection; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.hasSize; - - -@Testcontainers -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ReadControllerTest { - - - @Container - @ServiceConnection - static PostgreSQLContainer DATABASE = - new PostgreSQLContainer<>("postgres:15-alpine") - .withUsername("postgres") - .withPassword("postgres") - .withInitScript("pg/postgres-sakila-schema.sql") // inside src/test/resources - .withDatabaseName("postgres"); - - @LocalServerPort - private Integer port; - - @BeforeAll - static void beforeAll() { - DATABASE.start(); - } - - @AfterAll - static void afterAll() { - DATABASE.stop(); - } - - - - @BeforeEach - void setUp() { - RestAssured.baseURI = "http://localhost:" + port; - RestAssured.defaultParser = Parser.JSON; - - } - - @Test - void shouldSelectFields() { - - given() - .contentType(ContentType.JSON) - .accept(ContentType.JSON) - .headers("Accept-Profile", "public") - .when() - .get("/actor") - .then() - .statusCode(200) - .body(".", hasSize(2)); - } -}