/*
* Copyright (C) 2013-2017 NTT DATA Corporation
*
* 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 org.terasoluna.tourreservation.domain.service.reserve;
import org.junit.*;
import org.junit.runner.RunWith;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.support.WithSecurityContext;
import org.springframework.security.test.context.support.WithSecurityContextFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.terasoluna.gfw.common.date.jodatime.JodaTimeDateFactory;
import org.terasoluna.tourreservation.domain.model.*;
import org.terasoluna.tourreservation.domain.repository.reserve.ReserveRepository;
import org.terasoluna.tourreservation.domain.repository.tourinfo.TourInfoRepository;
import org.terasoluna.tourreservation.domain.service.userdetails.ReservationUserDetails;
import javax.inject.Inject;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ReserveServiceImplSecurityTest {
private static final String CUSTOMER_A = "C0000001";
private static final String CUSTOMER_B = "C0000002";
// Mock repository is define at the default bean definition file for this test case class.
@Inject
ReserveRepository mockReserveRepository;
@Inject
TourInfoRepository tourInfoRepository;
@Inject
ReserveService reserveService;
@Inject
JodaTimeDateFactory dateFactory;
@Before
public void resetMocks() {
reset(mockReserveRepository, tourInfoRepository);
}
@Test
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testFindOneForOwnerReservation() {
// setup
{
setUpMockReserveRepository(CUSTOMER_A, "R000000001");
}
// test
Reserve reserve;
{
reserve = reserveService.findOneWithTourInfo("R000000001");
}
// assert
{
assertThat(reserve.getReserveNo(), is("R000000001"));
assertThat(reserve.getCustomer().getCustomerCode(), is(CUSTOMER_A));
}
}
@Test
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testFindOneForNotFound() {
// setup
{
// Nothing
// ReserveRepository#findOne return null.
}
// test
Reserve reserve;
{
reserve = reserveService.findOneWithTourInfo("R000000001");
}
// assert
{
assertThat(reserve, nullValue());
}
}
@Test(expected = AccessDeniedException.class)
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testFindOneForOtherOwnerReservation() {
// setup
{
setUpMockReserveRepository(CUSTOMER_B, "R000000001");
}
// test
{
reserveService.findOneWithTourInfo("R000000001");
}
}
@Test
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testUpdateForOwnerReservation() {
// setup
{
setUpMockReserveRepository(CUSTOMER_A, "R000000001");
}
// test
ReservationUpdateOutput output;
{
ReservationUpdateInput input = new ReservationUpdateInput();
input.setReserveNo("R000000001");
input.setAdultCount(1);
input.setChildCount(1);
output = reserveService.update(input);
}
// assert
{
verify(mockReserveRepository, times(1)).update(
(Reserve) anyObject());
assertThat(output.getReserve().getReserveNo(), is("R000000001"));
assertThat(output.getReserve().getCustomer().getCustomerCode(),
is(CUSTOMER_A));
}
}
@Test
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testUpdateForOtherOwnerReservation() {
// setup
{
setUpMockReserveRepository(CUSTOMER_B, "R000000001");
}
// test
{
ReservationUpdateInput input = new ReservationUpdateInput();
input.setReserveNo("R000000001");
try {
reserveService.update(input);
fail();
} catch (AccessDeniedException e) {
// as expected
}
}
// assert
{
verify(mockReserveRepository, never())
.update((Reserve) anyObject());
}
}
@Test
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testCancelForOwnerReservation() {
// setup
{
setUpMockReserveRepository(CUSTOMER_A, "R000000001");
}
// test
{
reserveService.cancel("R000000001");
}
// assert
{
verify(mockReserveRepository, times(1)).delete("R000000001");
}
}
@Test
@WithMockCustomer(customerCode = CUSTOMER_A)
public void testCancelForOtherOwnerReservation() {
// setup
{
setUpMockReserveRepository(CUSTOMER_B, "R000000001");
}
// test
{
try {
reserveService.cancel("R000000001");
fail();
} catch (AccessDeniedException e) {
// as expected
}
}
// assert
{
verify(mockReserveRepository, never()).delete("R000000001");
}
}
/**
* Set up return object of {@link ReserveRepository}'s method.
* <p>
* This method set up return object of following methods.
* <ul>
* <li>{@link ReserveRepository#findOne}</li>
* <li>{@link ReserveRepository#findOneForUpdate}</li>
* </ul>
* @param customerCode customer code of reservation owner
* @param reserveNo reserve number of reservation
*/
private void setUpMockReserveRepository(String customerCode,
String reserveNo) {
Reserve reserve = new Reserve(reserveNo);
reserve.setCustomer(new Customer(customerCode));
reserve.setTourInfo(new TourInfo("01"));
when(mockReserveRepository.findOne(reserveNo)).thenReturn(reserve);
when(mockReserveRepository.findOneForUpdate(reserveNo)).thenReturn(
reserve);
TourInfo tourInfo = new TourInfo("01");
tourInfo.setDepDay(dateFactory.newDateTime().plusDays(8).toDate());
tourInfo.setDeparture(new Departure());
tourInfo.setArrival(new Arrival());
reserve.setTourInfo(tourInfo);
when(tourInfoRepository.findOneWithDetails(tourInfo.getTourCode()))
.thenReturn(tourInfo);
}
@WithSecurityContext(factory = WithMockCustomerSecurityContextFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@interface WithMockCustomer {
String customerCode();
}
static class WithMockCustomerSecurityContextFactory
implements
WithSecurityContextFactory<WithMockCustomer> {
@Override
public SecurityContext createSecurityContext(
WithMockCustomer mockCustomer) {
SecurityContext context = SecurityContextHolder
.createEmptyContext();
ReservationUserDetails userDetails = new ReservationUserDetails(new Customer(mockCustomer
.customerCode()));
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, "dummyPassword", userDetails
.getAuthorities());
context.setAuthentication(auth);
return context;
}
}
}