I want to generate a changelog file automatically via one of the maven liquibase plugin commands. The changelog should include a changeset for creating a database table for the DiscountCode entity. Would diff be the correct plugin command for this case?
#Entity
#Table(name = "discount_code")
public class DiscountCode {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long discountId;
private String discountCode;
private LocalDate expiration;
private BigDecimal discountValue;
public DiscountCode() {}
public DiscountCode(String discountCode, LocalDate expiration, BigDecimal discountValue) {
this.discountCode = discountCode;
this.expiration = expiration;
this.discountValue = discountValue;
}
public Long getDiscountId() {
return discountId;
}
public void setDiscountId(Long discountId) {
this.discountId = discountId;
}
public String getDiscountCode() {
return discountCode;
}
public void setDiscountCode(String discountCode) {
this.discountCode = discountCode;
}
public LocalDate getExpiration() {
return expiration;
}
public void setExpiration(LocalDate expiration) {
this.expiration = expiration;
}
public BigDecimal getDiscountValue() {
return discountValue;
}
public void setDiscountValue(BigDecimal discountValue) {
this.discountValue = discountValue;
}
#Override
public String toString() {
return (
"DiscountCode{" +
"discountId=" +
discountId +
", discountCode='" +
discountCode +
'\'' +
", expiration=" +
expiration +
", discountValue=" +
discountValue +
'}'
);
}
}
These are the available liquibase commands:
The solution is using the Liquibase Hibernate plugin.
The plugin configuration:
<plugins>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.liquibase.ext</groupId>
<artifactId>liquibase-hibernate4</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.7.3.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
Liquibase properties:
changeLogFile=classpath:liquibase-changeLog.xml
url=jdbc:mysql://localhost:3306/oauth_reddit
username=tutorialuser
password=tutorialmy5ql
driver=com.mysql.jdbc.Driver
referenceUrl=hibernate:spring:org.baeldung.persistence.model
?dialect=org.hibernate.dialect.MySQLDialect
diffChangeLogFile=src/main/resources/liquibase-diff-changeLog.xml
View this page for further information: https://www.baeldung.com/liquibase-refactor-schema-of-java-app
Related
I'm trying to connect my Springboot aplication to MongoDb. When i ran my application and i got this error:
Description:
Field userRepo in com.universitem.service.Impl.UserDetailsServiceImpl required a bean of type 'com.universitem.repository.UserRepository' that could not be found.
Action:
Consider defining a bean of type 'com.universitem.repository.UserRepository' in your configuration.
application.properties file:
spring.jpa.hibernate.ddl-auto=update
spring.data.mongodb.uri= /includes the uri
spring.data.mongodb.database=test
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
universitem.app.secret=UniversityToken
universitem.expires.in=120000
refresh.token.expires.in=604800
Main file :
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
#EnableJpaRepositories(basePackages = {"com.universitem.repository"})
public class UniversitemApplication {
public static void main(String[] args) {
SpringApplication.run(UniversitemApplication.class, args);
}
}
Security Configuration file:
#Configuration
#EnableWebSecurity
#Data
public class SecurityConfig {
private UserDetailsServiceImpl userDetailsService;
private JwtAuthenticationEntryPoint handler;
public SecurityConfig(UserDetailsServiceImpl userDetailsService, JwtAuthenticationEntryPoint handler) {
this.userDetailsService = userDetailsService;
this.handler = handler;
}
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()
.and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(handler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/comment/getAllUniversityComment{universityId}")
.permitAll()
.antMatchers(HttpMethod.GET, "/university/getAll")
.permitAll()
.antMatchers(HttpMethod.POST, "/userType/add")
.permitAll()
.antMatchers(HttpMethod.POST, "/universityType/add")
.permitAll()
.antMatchers(HttpMethod.GET, "/userType/getAll")
.permitAll()
.antMatchers("/userAuth/**")
.permitAll()
.anyRequest().authenticated();
httpSecurity.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
}
User Repository file:
#Repository
public interface UserRepository extends JpaRepository<User,Long> {
User findByUserName(String userName);
User findByUserMail(String userMail);
}
User Details Service Implementation file:
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepo;
#Override
public UserDetails loadUserByUsername(String userMail) throws UsernameNotFoundException {
User user =userRepo.findByUserMail(userMail);
return JwtUserDetails.create(user);
}
public UserDetails loadUserById(Long userId) {
User user = userRepo
.findById(userId).get();
return JwtUserDetails.create(user);
}
}
pom.xml file:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
I tried to add scanBasePackages to #SpringBootApplication like below. Actually database has been started but when i tried to sent request i got 404 Not Found error on postman.
#SpringBootApplication(scanBasePackages = {"com.universitem.repository"}, exclude = {SecurityAutoConfiguration.class})
I am confused how to implement CamelCorrelationID/JMSCorrelationID in a way where each application listen to its own response from server using messaging system. The queues are shared in this scenario. I have implemented my own CorrelationID to maintain the state of application. here I am using two client applications (Client-A and Client-B) sending/receiving the request to/from server
Currently both applications are reading each other responses from server, instead each application should listens to its own response based on CorrelationID passed in the header of request message.
Need help to resolve this.
Below are the code details:
Client-A code:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.camel.a</groupId>
<artifactId>CorrelationId-A</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CorrelationId-A</name>
<description>Understanding CorrelationId</description>
<properties>
<java.version>1.8</java.version>
<camel.version>3.11.0</camel.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-amqp-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
ClientARequestRoute.java
package com.camel.a.route;
import java.util.UUID;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class ClientARequestRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer://runOnce?repeatCount=1")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
UUID uuid = UUID.randomUUID();
String uniqueId = uuid.toString();
String testMsg = "Sending message from Client A with Unique Id as - " + uniqueId;
exchange.getIn().setHeader(Exchange.CORRELATION_ID, uniqueId);
exchange.getIn().setBody(testMsg, String.class);
}
})
.log("${body}")
.to("amqp:queue:RequestQueue");
}
}
ResponseServerRoute.java
package com.camel.a.route;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class ResponseServerRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("amqp:queue:ResponseQueue")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
String uniqueId = (String)exchange.getIn().getHeader(Exchange.CORRELATION_ID);
System.out.println("Received Correlation Id - " + uniqueId);
String msgReceived = (String) exchange.getIn().getBody(String.class);
exchange.getIn().setBody(msgReceived);
}
})
.log("${body}")
.end();
}
}
Client-B code:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.camel.b</groupId>
<artifactId>CorrelationId-B</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CorrelationId-B</name>
<description>Understanding CorrelationId</description>
<properties>
<java.version>1.8</java.version>
<camel.version>3.11.0</camel.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-amqp-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
ClientBRequestRoute.java
package com.camel.b.route;
import java.util.UUID;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class ClientBRequestRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer://runOnce?repeatCount=1")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
UUID uuid = UUID.randomUUID();
String uniqueId = uuid.toString();
String testMsg = "Sending message from Client B with Unique Id as - " + uniqueId;
exchange.getIn().setHeader(Exchange.CORRELATION_ID, uniqueId);
exchange.getIn().setBody(testMsg, String.class);
}
})
.log("${body}")
.to("amqp:queue:RequestQueue");
}
}
ResponseServerRoute.java
package com.camel.b.route;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class ResponseServerRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("amqp:queue:ResponseQueue")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
String uniqueId = (String)exchange.getIn().getHeader(Exchange.CORRELATION_ID);
System.out.println("Received Correlation Id - " + uniqueId);
String msgReceived = (String) exchange.getIn().getBody(String.class);
exchange.getIn().setBody(msgReceived);
}
})
.log("${body}")
.end();
}
}
I'm confused about the best way to configure the SJMS2 component. I'm using camel-spring-boot-starter in a simple test application and trying to write from a ProducerTemplate to ActiveMQ Artemis using the SJMS2 Camel Component. The component documentation says it handles things like connection caching and such which I would normally configure in my ConnectionFactory bean, so I'm getting the sense that I should defining less in my Configuration than I would without using Camel.
The documentation seems to lack a clear example of how to configure an jsms2 route and its ConnectionFactory when using Camel Spring. Is there a good example of this somewhere or could someone show me how that would look? Here's my current test application:
Spring Boot Application:
#SpringBootApplication
public class WebhookpublisherApplication implements CommandLineRunner {
#Autowired
private ProducerTemplate producerTemplate;
public static void main(String[] args) {
SpringApplication.run(WebhookpublisherApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
producerTemplate.sendBody("direct:test", "testBody");
}
}
Route:
#Component
public class RestToJmsRoute extends RouteBuilder {
#Override
public void configure() {
from("direct:test")
.log("Recieved a test body: ${body}")
.to("sjms2:topic:test-topic");
}
}
JMS Config (which is clearly not being used by the Camel component)
#Configuration
public class JmsConfig {
#Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() {
return new ActiveMQConnectionFactory("tcp://localhost:61616");
}
}
POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>cameljmstest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cameljmstest</name>
<description>test app</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-rest</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-sjms2</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The above is resulting in the following exception:
Caused by: java.lang.IllegalArgumentException: ConnectionResource or
ConnectionFactory must be configured for sjms2://test-topic
I ended up adding the following configuration class:
#Configuration
public class CamelContextConfig {
#Bean
public CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext context) {
Sjms2Component component = new Sjms2Component();
ActiveMQConnectionFactory activeMqConnectionFactory = new ActiveMQConnectionFactory("tcp://myArtemisHost:61616");
activeMqConnectionFactory.setUser("user");
activeMqConnectionFactory.setPassword("pass");
component.setConnectionFactory(activeMqConnectionFactory);
context.addComponent("sjms2", component);
}
#Override
public void afterApplicationStart(CamelContext camelContext) {
}
};
}
}
and then I changed my pom dependencies to these:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-sjms2-starter</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
I want to search something from database example i have three textfields
First Name , Last Name and Gender
if i input there
Some Firstname , Some Lastname , Male I want to search all the people with that certain name and gender and display it how do I do this?
Note: I am just new to Spring and just started learning thanks
Controller:
#RequestMapping(value = "/student/search", method = RequestMethod.GET)
public String searchStudent(#Param("name") String name, #Param("type") String type, Map<String, Object> model) {
Map<String, String> params = new HashMap<String, String>();
params.put("name", name);
params.put("type", gender);
model.put("students",studentRepository.findAll(StudentSpecification.search(params)));
return "/students/list";
}
}
Specification:
public static Specification<Student> search(final Map<String, String> params) {
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<Predicate>();
params.forEach((k, v) -> {
if (StringUtils.equals(k, "name")) {
if (StringUtils.isNotBlank(v)) {
Predicate hasFirstName =
criteriaBuilder.like(root.join("user").<String>get("firstName"), "%" + v + "%");
Predicate hasLastName =
criteriaBuilder.like(root.join("user").<String>get("lastName"), "%" + v + "%");
predicates.add(criteriaBuilder.or(hasFirstName, hasLastName));
}
}
});
return criteriaBuilder.and(predicates.toArray(new Predicate[] {}));
};
}
}
I presume from your code that you are using Spring data jpa, with specification, right?
if so, you need to generate MetaModel of your entities, add the code below if you are using maven, and this will do it for you
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.0.5</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>4.3.6.Final</version>
</dependency>
</dependencies>
</plugin>
I suppose you have an entity called Student, this plugin declaration will generate a classe suffixed with underscore 'Student_'
and then you could implement the specification interface, something like this
public class StudentSpecification {
public static Specification<Student> search(final Map<String, String> params) {
return new Specification<Student>() {
#Override
public Predicate toPredicate(Root<Student> studentRoot, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate res = null;
if(params.containKey("name"))
res = cb.equal(studentRoot.get(Student_.name), params.get("name"));
if(params.containKey("type"))
if(res ==null)
res = cb.equal(studentRoot.get(Student_.name), params.get("type"));
else
res = cb.and(res, cb.equal(studentRoot.get(Student_.name), params.get("type")));
return res;
}
}
}
and of course your StudentRepository class should extends JpaSpecificationExecutor, something like this
interface StudentRepository extends JpaSpecificationExecutor<Student> {
}
You can do this using #Query, add method in the repository:
#Query("SELECT e FROM STUDENT e WHERE e.name = ?1 AND e.type = ?2")
public List<student> findAll(String name, String type);
Use that method in the controller:
#RequestMapping(value = "/student/search", method = RequestMethod.GET)
public String searchStudent(#Param("name") String name, #Param("type") String type, Map<String, Object> model) {
model.put("students",studentRepository.findAll(name, type));
return "/students/list";
}
I wonder if there is any best practice for junit testing of Solr 3.6. I want to automate testing of the Solr schema. Earlier posts mentioned the EmbeddedSolrServer. This class seems to have been abandoned from any version between 1.4 an 3.6. I use Spring 3.0.x and Maven for the project.
The options I considered are:
writing a Junit Test Runner
put the jetty startup code in the #Before or #BeforeClass method
start a solr server in maven (probably not a good option)
put some code in the spring test-context
I've used something similar to what's on this page to run these kinds of tests, all done with EmbeddedSolrServer on Solr 3.4.0. This is a simple approach, but if you want to automate Solr schema testing, it could be enough and isn't hard to implement.
It basically boils down to:
Adding references to junit, solr-core, slf4j-simpleand servlet-apito your pom.xml:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<!-- dependencies needed for Solr integration test-->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-core</artifactId>
<version>1.4.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>test</scope>
</dependency>
And as an example test case, he adds this:
import java.io.IOException;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.util.AbstractSolrTestCase;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class SolrSearchConfigTest extends AbstractSolrTestCase {
private SolrServer server;
#Override
public String getSchemaFile() {
return "solr/conf/schema.xml";
}
#Override
public String getSolrConfigFile() {
return "solr/conf/solrconfig.xml";
}
#Before
#Override
public void setUp() throws Exception {
super.setUp();
server = new EmbeddedSolrServer(h.getCoreContainer(), h.getCore().getName());
}
#Test
public void testThatNoResultsAreReturned() throws SolrServerException {
SolrParams params = new SolrQuery("text that is not found");
QueryResponse response = server.query(params);
assertEquals(0L, response.getResults().getNumFound());
}
#Test
public void testThatDocumentIsFound() throws SolrServerException, IOException {
SolrInputDocument document = new SolrInputDocument();
document.addField("id", "1");
document.addField("name", "my name");
server.add(document);
server.commit();
SolrParams params = new SolrQuery("name");
QueryResponse response = server.query(params);
assertEquals(1L, response.getResults().getNumFound());
assertEquals("1", response.getResults().get(0).get("id"));
}
}
edit: I haven't used Solr in quite a while, but I think this could still be a good starting point.
This is my take on it. It doesn't extend AbstractSolrTestCase, just a regular test class.
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.core.CoreContainer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class EmbeddedSolrServerTest {
private static final int SUCCESS = 0;
private final String indexLocation = "tomcat7/apps/apache-solr-3.6.0";
private EmbeddedSolrServer server;
#Before
public void setUp() throws Exception {
System.setProperty("solr.solr.home", indexLocation);
CoreContainer coreContainer = new CoreContainer.Initializer().initialize();
server = new EmbeddedSolrServer(coreContainer, "collection1");
}
#After
public void tearDown() throws Exception {
server.shutdown();
removeIndexDirectory();
}
#Test
public void testSolrSchema01() throws Exception {
SolrInputDocument doc1 = new SolrInputDocument();
doc1.addField("id", "123");
doc1.addField("something_txt", "super wombat");
UpdateResponse ur = server.add(doc1);
assertThat(ur.getStatus(), is(SUCCESS));
server.commit();
QueryResponse response1 = server.query(new SolrQuery("*:*"));
assertThat(response1.getResults().getNumFound(), is(1L));
QueryResponse response2 = server.query(new SolrQuery("something_txt:*wombat*"));
assertThat(response2.getResults().getNumFound(), is(1L));
}
private void removeIndexDirectory() throws IOException {
File indexDir = new File(indexLocation, "data/index");
FileUtils.deleteDirectory(indexDir);
}
}
My POM has the following dependencies:
<properties>
<solr.version>3.6.0</solr.version>
<httpcomponents.version>4.3.2</httpcomponents.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>${solr.version}</version>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-core</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpcomponents.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>${httpcomponents.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
I've set up a separate project to keep all my Solr config in and run tests against it. The directory structure is:
solr-test
|--src
| |--test
|--tomcat7
` |--apps
|--apache-solr-3.6.0
|--conf
|--data
|--index
This seems to work well for me. This set up will also let you write tests using HttpSolrServer to test a remote server's schema.
Also, note the server.commit() call in the middle of the test. This needs to be there otherwise the Solr transaction isn't complete and the new document won't be visible.
I'm using https://github.com/moliware/travis-solr for my tests, maybe it's useful for you too.