// Copyright © 2015 HSL <https://www.hsl.fi>
// This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses.
package fi.hsl.parkandride.itest;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;
import com.jayway.restassured.specification.RequestSpecification;
import fi.hsl.parkandride.back.Dummies;
import fi.hsl.parkandride.core.domain.*;
import fi.hsl.parkandride.core.service.*;
import fi.hsl.parkandride.core.service.reporting.ReportParameters;
import fi.hsl.parkandride.front.UrlSchema;
import junit.framework.AssertionFailedError;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.assertj.core.api.SoftAssertionError;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.junit.Before;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import javax.inject.Inject;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import static com.jayway.restassured.RestAssured.given;
import static fi.hsl.parkandride.core.domain.Role.ADMIN;
import static fi.hsl.parkandride.core.domain.Role.OPERATOR;
import static fi.hsl.parkandride.core.domain.Role.OPERATOR_API;
import static fi.hsl.parkandride.front.ReportController.MEDIA_TYPE_EXCEL;
import static java.util.Arrays.asList;
import static java.util.Spliterator.ORDERED;
import static java.util.Spliterators.spliteratorUnknownSize;
import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;
import static org.joda.time.DateTimeConstants.MONDAY;
public abstract class AbstractReportingITest extends AbstractIntegrationTest {
protected static final DateTime BASE_DATE_TIME = new DateTime(2015, 9, 15, 12, 37);
protected static final DateTime ROUNDED_BASE_DATETIME = BASE_DATE_TIME.withMinuteOfHour(0);
protected static final LocalDate BASE_DATE = BASE_DATE_TIME.toLocalDate();
protected static final String MONTH_FORMAT = "M/yyyy";
protected static final String DATE_FORMAT = "d.M.yyyy";
protected static final String DATETIME_FORMAT = "d.M.yyyy HH:mm";
protected static final DateTime baseDate = BASE_DATE.toDateTime(new LocalTime("7:59")).withDayOfMonth(15);
protected static final DateTime mon = baseDate.withDayOfWeek(MONDAY);
protected static final DateTime tue = mon.plusDays(1);
protected static final DateTime wed = mon.plusDays(2);
protected static final DateTime fri = mon.plusDays(4);
protected static final DateTime sat = mon.plusDays(5);
protected static final DateTime sun = mon.plusDays(6);
protected static final DateTime initial = mon.minusMonths(1);
protected User adminUser;
protected User apiUser;
protected Hub hub;
protected Facility facility1;
protected Facility facility2;
protected Operator operator1;
protected Operator operator2;
protected User operator1User;
protected User operator2User;
protected User apiUser2;
@Inject Dummies dummies;
@Inject FacilityService facilityService;
@Inject PredictionService predictionService;
@Inject HubService hubService;
@Inject OperatorService operatorService;
@Inject TranslationService translationService;
@Inject MessageSource messageSource;
@Before
public void initialize() {
initFixture();
}
protected final void initFixture() {
devHelper.deleteAll();
long facilityId1 = dummies.createFacility();
long facilityId2 = dummies.createFacility();
long hubId = dummies.createHub(facilityId1, facilityId2);
hub = hubService.getHub(hubId);
facility1 = facilityService.getFacility(facilityId1);
facility2 = facilityService.getFacility(facilityId2);
operator1 = operatorService.getOperator(facility1.operatorId);
operator2 = operatorService.getOperator(facility2.operatorId);
operator1User = devHelper.createOrUpdateUser(new NewUser(1L, "operator", OPERATOR, facility1.operatorId, "operator"));
operator2User = devHelper.createOrUpdateUser(new NewUser(2L, "operator2", OPERATOR, facility2.operatorId, "operator"));
apiUser = devHelper.createOrUpdateUser(new NewUser(100L, "operator_api", OPERATOR_API, facility1.operatorId, "operator"));
apiUser2 = devHelper.createOrUpdateUser(new NewUser(101L, "Ooppera_api", OPERATOR_API, facility2.operatorId, "Ooppera"));
adminUser = devHelper.createOrUpdateUser(new NewUser(10L, "admin", ADMIN, null, "admin"));
}
// ---------------------
// HELPER METHODS
// ---------------------
protected static ReportParameters baseParams() {
return baseParams(BASE_DATE);
}
protected static ReportParameters baseParams(LocalDate referenceDate) {
final ReportParameters params = new ReportParameters();
params.startDate = referenceDate.dayOfMonth().withMinimumValue();
params.endDate = referenceDate.dayOfMonth().withMaximumValue();
return params;
}
static void printSheet(Sheet sheet) {
final DataFormatter dataFormatter = new DataFormatter();
List<List<String>> rows = new ArrayList<>();
for (Row row : sheet) {
List<String> r = new ArrayList<>();
for (Cell cell : row) {
r.add(dataFormatter.formatCellValue(cell));
}
rows.add(r);
}
printSheet(rows);
}
static void printSheet(List<List<String>> rows) {
for (List<String> row : rows) {
for (String cell : row) {
System.out.printf("%-30s", cell);
}
System.out.printf("%n");
}
}
protected static com.jayway.restassured.response.Header authorization(String authToken) {
return new com.jayway.restassured.response.Header(HttpHeaders.AUTHORIZATION, "Bearer " + authToken);
}
protected static Utilization utilize(CapacityType capacityType, Integer spacesAvailable, DateTime ts, Facility f) {
return utilize(capacityType, f.usages.first(), spacesAvailable, ts, f);
}
protected static Utilization utilize(CapacityType capacityType, Usage usage, Integer spacesAvailable, DateTime ts, Facility f) {
final Utilization utilization = new Utilization();
utilization.facilityId = f.id;
utilization.capacityType = capacityType;
utilization.spacesAvailable = spacesAvailable;
utilization.usage = usage;
utilization.timestamp = ts;
return utilization;
}
protected List<String> findRowWithColumn(Sheet sheet, int columnNumber, String content) {
for (int i = 0; i < sheet.getPhysicalNumberOfRows(); i++) {
final Row row = sheet.getRow(i);
final List<String> dataFromRow = getDataFromRow(row);
if (dataFromRow.contains(content)) {
return dataFromRow;
}
}
throw new NoSuchElementException(String.format("Row with column at %d: <%s> not found", columnNumber, content));
}
protected Response postToReportUrl(ReportParameters params, String reportType, User user) {
final Response whenPostingToReportUrl = whenPostingToReportUrl(params, reportType, user);
whenPostingToReportUrl
.then()
.assertThat().statusCode(HttpStatus.OK.value())
.assertThat().contentType(MEDIA_TYPE_EXCEL);
return whenPostingToReportUrl;
}
protected Response whenPostingToReportUrl(ReportParameters params, String reportType, User user) {
final RequestSpecification createRequest = createRequest(params, user);
return whenPostingToReportUrl(reportType, createRequest);
}
protected Response whenPostingToReportUrl(String reportType, RequestSpecification createRequest) {
return createRequest.when().post(UrlSchema.REPORT, reportType);
}
protected RequestSpecification createRequest(ReportParameters params, User user) {
final String authToken = devHelper.login(user.username).token;
return given().contentType(ContentType.JSON)
.accept(MEDIA_TYPE_EXCEL)
.header(RequestLogITest.authorization(authToken))
.body(params);
}
protected void withWorkbook(Response response, Consumer<Workbook> workbookConsumer) {
try (Workbook workbook = readWorkbookFrom(response)) {
workbookConsumer.accept(workbook);
} catch (IOException e) {
e.printStackTrace();
throw new AssertionFailedError(e.getMessage());
}
}
protected Workbook readWorkbookFrom(Response whenPostingToReportUrl) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(whenPostingToReportUrl.asByteArray())){
return WorkbookFactory.create(bais);
} catch (IOException | InvalidFormatException e) {
e.printStackTrace();
throw new AssertionFailedError(e.getMessage());
}
}
protected List<String> getDataFromRow(Sheet sheet, int rownum) {
final Row row = sheet.getRow(rownum);
return row == null ? null : getDataFromRow(row);
}
protected List<String> getDataFromRow(Row row) {
final DataFormatter dataFormatter = new DataFormatter();
return stream(spliteratorUnknownSize(row.cellIterator(), ORDERED), false)
.map(cell -> dataFormatter.formatCellValue(cell))
.collect(toList());
}
protected List<String> getDataFromColumn(Sheet sheet, int colnum) {
final DataFormatter dataFormatter = new DataFormatter();
return stream(spliteratorUnknownSize(sheet.rowIterator(), ORDERED), false)
.map(row -> row.getCell(colnum))
.map(cell -> dataFormatter.formatCellValue(cell))
.collect(toList());
}
protected List<String> getSheetNames(Workbook workbook) {
return IntStream.range(0, workbook.getNumberOfSheets())
.mapToObj(i -> workbook.getSheetName(i))
.collect(toList());
}
void checkSheetContents(Response response, int sheetIndex, List<String>... rows) {
withWorkbook(response, workbook -> checkSheetContents(workbook, sheetIndex, rows));
}
void checkSheetContents(Workbook workbook, int sheetIndex, List<String>... rows) {
try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
checkSheetContents(softly, workbook, sheetIndex, rows);
} catch (SoftAssertionError sae) {
System.out.println("===========\nACTUAL\n===========");
printSheet(workbook.getSheetAt(sheetIndex));
System.out.println("===========\nEXPECTED\n===========");
printSheet(asList(rows));
throw sae;
}
}
void checkSheetContents(AutoCloseableSoftAssertions softly, Workbook workbook, int sheetIndex, List<String>... rows) {
Sheet sheet = workbook.getSheetAt(sheetIndex);
softly.assertThat(sheet.getPhysicalNumberOfRows()).as("Number of rows").isEqualTo(rows.length);
for (int i = 0; i < rows.length; i++) {
final List<String> dataFromRow = getDataFromRow(sheet, i);
softly.assertThat(dataFromRow).as("Row index %d", i).containsExactlyElementsOf(rows[i]);
}
}
}