squash.booking.lambdas.GetBookingsLambdaTest.java Source code

Java tutorial

Introduction

Here is the source code for squash.booking.lambdas.GetBookingsLambdaTest.java

Source

/**
 * Copyright 2015-2017 Robin Steel
 *
 * 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
 *
 *    http://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 squash.booking.lambdas;

import static org.junit.Assert.assertTrue;

import squash.booking.lambdas.core.Booking;
import squash.booking.lambdas.core.IBookingManager;
import squash.booking.lambdas.core.ILifecycleManager;
import squash.booking.lambdas.core.ILifecycleManager.LifecycleState;

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Tests the {@link GetBookingsLambda GetBookings} lambda.
 * 
 * @author robinsteel19@outlook.com (Robin Steel)
 */
public class GetBookingsLambdaTest {
    Mockery mockery = new Mockery();
    TestGetBookingsLambda getBookingsLambda;
    Context mockContext;
    ILifecycleManager mockLifecycleManager;
    List<Booking> expectedBookings;
    LambdaLogger mockLogger;
    String name;
    Integer court;
    Integer slot;
    Booking booking;
    List<Booking> bookings;
    LocalDate fakeCurrentDate;
    String fakeCurrentDateString;
    String redirectUrl;
    String genericExceptionMessage;

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Before
    public void beforeTest() throws Exception {
        mockery = new Mockery();
        getBookingsLambda = new TestGetBookingsLambda();
        getBookingsLambda.setBookingManager(mockery.mock(IBookingManager.class));

        // Set up the valid date range
        List<String> validDates = new ArrayList<>();
        fakeCurrentDate = LocalDate.of(2015, 10, 6);
        fakeCurrentDateString = fakeCurrentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        validDates.add(fakeCurrentDateString);
        validDates.add(fakeCurrentDate.plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        getBookingsLambda.setValidDates(validDates);

        // Set up mock context
        mockContext = mockery.mock(Context.class);
        mockery.checking(new Expectations() {
            {
                ignoring(mockContext);
            }
        });

        // Set up mock logger
        mockLogger = mockery.mock(LambdaLogger.class);
        mockery.checking(new Expectations() {
            {
                ignoring(mockLogger);
            }
        });

        // Set up mock lifecycle manager
        mockLifecycleManager = mockery.mock(ILifecycleManager.class);
        mockery.checking(new Expectations() {
            {
                allowing(mockLifecycleManager).getLifecycleState();
                will(returnValue(new ImmutablePair<LifecycleState, Optional<String>>(LifecycleState.ACTIVE,
                        Optional.empty())));
            }
        });
        getBookingsLambda.setLifecycleManager(mockLifecycleManager);

        // Set up some typical bookings data that the tests can use
        name = "A.Playera/B.Playerb";
        court = 5;
        slot = 3;
        booking = new Booking(court, slot, name);
        bookings = new ArrayList<>();
        bookings.add(booking);
        redirectUrl = "redirectUrl.html";

        // Exception message thrown to apigateway invocations has a redirecturl
        // appended
        genericExceptionMessage = "Apologies - something has gone wrong. Please try again." + redirectUrl;
    }

    @After
    public void afterTest() {
        mockery.assertIsSatisfied();
    }

    // Define a test sublass with some overrides to facilitate testing
    public class TestGetBookingsLambda extends GetBookingsLambda {
        private IBookingManager bookingManager;
        private ILifecycleManager lifecycleManager;
        private List<String> validDates;

        public void setBookingManager(IBookingManager bookingManager) {
            this.bookingManager = bookingManager;
        }

        @Override
        protected IBookingManager getBookingManager(LambdaLogger logger) throws Exception {
            return bookingManager;
        }

        public void setLifecycleManager(ILifecycleManager lifecycleManager) {
            this.lifecycleManager = lifecycleManager;
        }

        @Override
        protected ILifecycleManager getLifecycleManager(LambdaLogger logger) throws Exception {
            return lifecycleManager;
        }

        public void setValidDates(List<String> validDates) {
            this.validDates = validDates;
        }

        @Override
        protected List<String> getValidDates() {
            return validDates;
        }
    }

    @Test
    public void testGetBookingsThrowsCorrectExceptionIfDateOutsideValidRange() throws Exception {

        // ARRANGE
        thrown.expect(Exception.class);
        thrown.expectMessage("The booking date is outside the valid range. Please try again.redirectUrl");

        // ACT
        // Ask for the bookings for an invalid date - which should throw
        GetBookingsLambdaRequest request = new GetBookingsLambdaRequest();
        request.setDate("2015-10-08"); // Invalid - too far in future
        request.setRedirectUrl(redirectUrl);

        getBookingsLambda.getBookings(request, mockContext);
    }

    @Test
    public void testGetBookingsThrowsCorrectExceptionWhenBookingManagerThrowsAce() throws Exception {
        // N.B. The precise exceptions thrown by the lambdas are important as they
        // get matched by a regex in ApiGateway to be reported to the user.

        doTestGetBookingsThrowsCorrectExceptionWhenBookingManagerThrows(new AmazonClientException("Grrr.."));
    }

    @Test
    public void testGetBookingsThrowsCorrectExceptionWhenBookingManagerThrowsAse() throws Exception {
        // N.B. The precise exceptions thrown by the lambdas are important as
        // they get matched by a regex in ApiGateway to be reported to the user.

        doTestGetBookingsThrowsCorrectExceptionWhenBookingManagerThrows(new AmazonServiceException("Grrr.."));
    }

    @Test
    public void testGetBookingsThrowsCorrectExceptionWhenBookingManagerThrowsSomethingElse() throws Exception {
        // When any exception other than those explicitly checked for is thrown
        // we should convert it as described here.

        doTestGetBookingsThrowsCorrectExceptionWhenBookingManagerThrows(new IllegalAccessException("Grrr.."));
    }

    public void doTestGetBookingsThrowsCorrectExceptionWhenBookingManagerThrows(Exception exception)
            throws Exception {
        // N.B. The precise exceptions thrown by the lambdas are important as they
        // get matched by a regex in ApiGateway to be reported to the user.

        // ARRANGE
        thrown.expect(Exception.class);
        thrown.expectMessage(genericExceptionMessage);

        // Make getBookings call throw
        mockery.checking(new Expectations() {
            {
                allowing(getBookingsLambda.getBookingManager(mockLogger)).getBookings(with(aNonNull(String.class)),
                        with.booleanIs(anything()));
                will(throwException(exception));
            }
        });

        // ACT
        // Ask for the bookings for a valid date
        GetBookingsLambdaRequest request = new GetBookingsLambdaRequest();
        request.setDate(fakeCurrentDateString);
        request.setRedirectUrl(redirectUrl);

        getBookingsLambda.getBookings(request, mockContext);
    }

    @Test
    public void testGetBookingsCorrectlyCallsBookingManager() throws Exception {

        // Test happy path for getBookings: we verify the call gets forwarded
        // to the IBookingManager, and the returned bookings are wired back.

        // ARRANGE
        // Set up some expected bookings, so we can check they get forwarded on back
        // to us
        mockery.checking(new Expectations() {
            {
                oneOf(getBookingsLambda.getBookingManager(mockLogger))
                        .getBookings(with(equal(fakeCurrentDateString)), with.booleanIs(anything()));
                will(returnValue(bookings));
            }
        });

        // ACT
        // Ask for the bookings for a valid date
        GetBookingsLambdaRequest request = new GetBookingsLambdaRequest();
        request.setDate(fakeCurrentDateString);

        GetBookingsLambdaResponse response = getBookingsLambda.getBookings(request, mockContext);

        // Assert
        // Check returned bookings are wired back
        assertTrue("Bookings returned by getBookings were not as expected", response.getBookings() == bookings);
    }
}