Background
The Video team at a large online retailer runs the catalogue behind its movie store. This service answers the store's search box and the movie pages: it finds published movies by title, director or cast and returns them a page at a time, most popular first. Since the last release, customers and the QA team have been reporting odd search results.
How the system works
Movies
A movie has an id, a title, a release year, a director, stars (the credited cast, in billing order), a popularity score from 0 to 100 and a status: DRAFT, PUBLISHED or RETIRED. Only PUBLISHED movies are ever shown to customers, in search results or on movie pages. Movies imported without a credited cast (most documentaries) have no stars at all; the API shows them with "stars": [].
Queries
The query q is normalised before searching: leading and trailing whitespace is removed, every run of whitespace inside it becomes a single space, and it is lower-cased. " The LONG night " becomes "the long night". After normalising, the query must be 2 to 60 characters long, both included (400 INVALID_QUERY otherwise, including when q is missing).
Matching
Catalogue text is normalised the same way, and a text matches when it contains the query anywhere, even inside a word: "ight" matches "The Long Night". The field parameter decides what is searched:
field | A movie matches when |
|---|---|
title | its title matches |
stars | at least one of its stars matches |
all | its title, its director or at least one of its stars matches |
field is accepted in any case (STARS is stars). When it is left out, it is all. Any other value is 400 INVALID_FIELD.
Order and pages
Matching movies are ordered by popularity, highest first; then by year, newest first; then by title, alphabetically and ignoring case; then by id.
page (1 or more, default 1) and size (1 to 50, both included, default 10) pick one page of that list: page 1 is the first size movies, page 2 the next size, and so on. Both must be whole numbers (400 INVALID_PAGE otherwise). A page past the end is empty. total is the number of matching movies on all pages together.
API
| Method and path | Parameters | Success |
|---|---|---|
GET /api/catalogue/search | q, optional field, page, size | 200 {query, field, page, size, total, results} |
GET /api/catalogue/movies/{id} | 200 the movie; 404 MOVIE_NOT_FOUND if there is no such movie or it isn't published |
In the search response, query is the normalised query, field is title, stars or all in lower case, and results holds this page's movies in result order. A movie in a response is {id, title, year, director, stars, popularity}. Errors return {"error": "<CODE>", "message": "..."}.
Project structure
src/main/java/com/bugnik/movies/
MoviesApplication.java Spring Boot entry point
model/ Movie, MovieStatus, SearchField
repository/MovieRepository.java the catalogue (in memory)
service/MovieSearchService.java query and paging checks, search, lookups
service/SearchResult.java one page of a search
service/CatalogueException.java errors with a status and a code
util/SearchText.java text normalisation and matching
util/MovieMatcher.java which movies match a query in a field
util/MovieOrder.java the result order
web/ MovieController, MovieSummary, SearchResponse, ApiError, ApiExceptionHandler
src/test/java/com/bugnik/movies/ unit and MockMvc tests
Your task
Customers and the QA team report that:
- Customers say the search box misses films they know are in the store, although the movie pages open fine.
- The store's "Next page" button disappears after the first page, even when there are more results.
- A few ordinary searches fail with a server error.
Find and fix the defects so that all tests pass.
- Do not modify
src/test/orpom.xml. - Keep your changes minimal. Fix the defects; don't rewrite modules.
- Additional hidden tests check the behaviour described in this README.