Showing posts with label REST. Show all posts
Showing posts with label REST. Show all posts

2014/05/12

Testing REST Service in Spring Boot with RestTemplate

I have decided to add my bit to Spring Boot's well-deserved popularity -- one must appreciate how fast you can create a simple application without compromising the design.

Of course, if you take your work seriously there is no way you can get by without  tests. An example is better than hours of explaining -- below you see testing of real service (no mocks) running locally:
  • in first case sending POST request to create a new record and creating an object to from the response
  • in second case GET request is send and the failure message is treaded as "raw" JSON


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Collections;

import static org.hamcrest.Matchers.*;
import static org.springframework.test.util.MatcherAssertionErrors.assertThat;


@RunWith (SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration (classes = Config.class)
@WebAppConfiguration
@IntegrationTest
public class UserControllerTest
{
  final String BASE_URL = "http://localhost:9999/customer/";

  @Test
  public void shouldCreateNewUser() {

    final String USER_NAME = "Leif Ericson";
    final String USER_ADDRESS = "Vinland";

    User user = new User();
    user.setName(USER_NAME);
    user.setAddress(USER_ADDRESS);

    RestTemplate rest = new TestRestTemplate();

    ResponseEntity<User> response = 
       rest.postForEntity(BASE_URL, user, User.class, Collections.EMPTY_MAP);
    assertThat( response.getStatusCode() , equalTo(HttpStatus.CREATED));

    User userCreated = response.getBody();
    assertThat( userCreated.getId() , notNullValue() );
    assertThat( userCreated.getName() , equalTo(CUSTOMER_NAME) );
    assertThat( userCreated.getAddress() , equalTo(CUSTOMER_ADDRESS) );
  }

  @Test
  public void shouldFailToGetUnknownUser()
  throws IOException {

    final int UNKNOWN_ID = Integer.MAX_VALUE;
    final String EXPECTED_ANSWER_MESSAGE = "user with id : '" + UNKNOWN_ID+ "' does not exist";

    RestTemplate rest = new TestRestTemplate();

    ResponseEntity<String> response = rest.getForEntity(BASE_URL + UNKNOWN_ID, String.class);

    assertThat( response.getStatusCode() , equalTo(HttpStatus.NOT_FOUND));

    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode responseJson = objectMapper.readTree(response.getBody());
    JsonNode messageJson = responseJson.path("message");

    assertThat( messageJson.isMissingNode() , is(false) );
    assertThat( messageJson.asText() , equalTo(EXPECTED_ANSWER_MESSAGE) );
  }
}

2011/07/21

Elasticsearch in 10 Minutes

We produce a lot of PDF files with documentation. Way too many. The problem is that nobody knows to which document this or that documentation belongs or where it really is.

Some fulltext would help. I recently stumbled over elasticsearch - schema-free, scalable search engine based on Apache Lucene. I decided to give it a try -  not because its distributed nature, but for its REST interface.

I did following  4 steps to get simple fulltext search working:

1/ Extracted text from PDFs using pdftotext and simple bash one-liner.
for FILE in $(ls *.pdf); do pdftotext $FILE; done

2/ Created Java Maven project. The elasticsearch's pom.xml I found did not contain necessary dependencies, so I had to add them to my pom.xml and the result is a bit messy.
<?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 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>docsearch</groupId>
    <artifactId>docsearch</artifactId>
    <version>1.0</version>

    <repositories>
     <repository>
       <id>fuse</id>
       <url>http://repo.fusesource.com/maven2/</url>
     </repository>
    </repositories>

    <dependencies>
      <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>0.16.0</version>
      </dependency>

      <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-core</artifactId>
        <version>3.3.0</version>
      </dependency>           

      <dependency>                  
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-analyzers</artifactId>   
        <version>3.3.0</version>                            
      </dependency>                                               

      <dependency>                                                      
        <groupId>org.apache.lucene</groupId>                                    
        <artifactId>lucene-snowball</artifactId>                                          
        <version>3.0.3</version>                                                                    
      </dependency>                                                                                         
                                                                                                            
      <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-fast-vector-highlighter</artifactId>
        <version>3.0.3</version>
      </dependency>

      <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-highlighter</artifactId>
        <version>2.4.0</version>
      </dependency>

      <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-queries</artifactId>
        <version>2.4.0</version>
      </dependency>

    </dependencies>

</project> 
 
3/ Downloaded the elesticsearch release and started it.

4/ Wrote a simple Java code to iterate over files, read them line-by-line and feed them to the running elasticsearch service:

import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.io.Files;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.node.Node;

import java.io.*;

import static java.lang.System.out;
import static org.elasticsearch.common.xcontent.XContentFactory.*;
import static org.elasticsearch.node.NodeBuilder.*;

public class Main
{
  final static String dataDirName = "/tmp/doc";

  public static void main (String[] args)
  {
     File dataDir = new File(dataDirName);

     if ( dataDir.exists() && dataDir.isDirectory() )
     {
        File[] files = dataDir.listFiles
        (
           new FilenameFilter()
           {  
              public boolean accept(File dir, String name)
              { return name.endsWith("txt"); }   
           }
        );
  
        // esearch client creation
        Node node = nodeBuilder().node();
        Client client = new TransportClient()
                       .addTransportAddress(new InetSocketTransportAddress("localhost", 9300));
  
        String indexName = "docs";
        String docType = "doc";
        String docId = null;
        for (File file : files)
        {
           try
           {
              BufferedReader reader = new BufferedReader ( new FileReader(file) );
              String line;
              StringBuilder fileContent = new StringBuilder();
              while ( (line = reader.readLine()) != null)
              { fileContent.append(line); }

              docId = file.getName();
              IndexResponse response =
                client.prepareIndex(indexName,docType,docId).setSource
                  ( jsonBuilder() .startObject().field("content", fileContent).endObject() )
                .execute().actionGet();
           }
           catch (FileNotFoundException ex) { ex.printStackTrace(); }
           catch (IOException ex) { ex.printStackTrace(); }
        }

        node.close();
     }
  }
}