client: serialize LocalDate as 2009-01-01 (FINERACT-1234)
This commit is contained in:
committed by
Petri Tuomola
parent
af1509abee
commit
ff0db483cd
@@ -37,7 +37,8 @@ dependencies {
|
||||
|
||||
testImplementation(
|
||||
'org.junit.jupiter:junit-jupiter-api:5.7.0',
|
||||
'com.google.truth:truth:1.0.1'
|
||||
'com.google.truth:truth:1.0.1',
|
||||
'com.google.truth.extensions:truth-java8-extension:1.0.1'
|
||||
)
|
||||
testRuntimeOnly(
|
||||
'org.junit.jupiter:junit-jupiter-engine:5.7.0'
|
||||
|
||||
@@ -147,6 +147,15 @@ import retrofit2.converter.scalars.ScalarsConverterFactory;
|
||||
*/
|
||||
public final class FineractClient {
|
||||
|
||||
/**
|
||||
* Constant to be used in requests where Fineract's API requires a dateFormat to be given. This matches the format
|
||||
* in which LocalDate instances are serialized. (BTW: In a Java client API, it seems weird to have strong LocalDate
|
||||
* (not String) instances, and then have to specify its format, see
|
||||
* https://issues.apache.org/jira/browse/FINERACT-1233.)
|
||||
*/
|
||||
// Matching org.apache.fineract.client.util.JSON.LocalDateTypeAdapter.formatter
|
||||
public static final String DATE_FORMAT = "yyyy-mm-dd";
|
||||
|
||||
private final Retrofit retrofit;
|
||||
|
||||
public final AccountingClosureApi glClosures;
|
||||
|
||||
@@ -97,22 +97,21 @@ class JSON {
|
||||
}
|
||||
|
||||
/**
|
||||
* GSON TypeAdapter for JSR-310 LocalDate type in Fineract API Format (<tt>[2009,1,1]</tt>).
|
||||
* GSON TypeAdapter for JSR-310 LocalDate type, which Fineract API's RETURNS as JSON array in the
|
||||
* <tt>[2009,1,1]</tt> format, but EXPECTS as String not Array and with a locale and dateFormat. Weird, but so it is
|
||||
* (see FINERACT-1220 & FINERACT-1233).
|
||||
*/
|
||||
public static class LocalDateTypeAdapter extends TypeAdapter<LocalDate> {
|
||||
|
||||
// Now unused: private final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||
// NB this format is referenced from org.apache.fineract.client.util.FineractClient.DATE_FORMAT
|
||||
private final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, LocalDate date) throws IOException {
|
||||
if (date == null) {
|
||||
out.nullValue();
|
||||
} else {
|
||||
out.beginArray();
|
||||
out.value(date.getYear());
|
||||
out.value(date.getMonthValue());
|
||||
out.value(date.getDayOfMonth());
|
||||
out.endArray();
|
||||
out.value(formatter.format(date));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.apache.fineract.client.testutil;
|
||||
|
||||
import com.google.common.truth.FailureMetadata;
|
||||
import com.google.common.truth.Subject;
|
||||
import com.google.common.truth.Truth;
|
||||
import java.io.IOException;
|
||||
import javax.annotation.Nullable;
|
||||
import retrofit2.Call;
|
||||
|
||||
/**
|
||||
* Google Truth Extension for Retrofit Call.
|
||||
*
|
||||
* @author Michael Vorburger.ch
|
||||
*/
|
||||
public class CallSubject extends Subject {
|
||||
|
||||
// as per https://truth.dev/extension
|
||||
|
||||
public static CallSubject assertThat(@Nullable Call<?> actual) {
|
||||
return Truth.assertAbout(calls()).that(actual);
|
||||
}
|
||||
|
||||
public static Factory<CallSubject, Call<?>> calls() {
|
||||
return CallSubject::new;
|
||||
}
|
||||
|
||||
private final Call<?> actual;
|
||||
|
||||
protected CallSubject(FailureMetadata metadata, @Nullable Call<?> actual) {
|
||||
super(metadata, actual);
|
||||
this.actual = actual;
|
||||
}
|
||||
|
||||
public void hasHttpStatus(int expectedHttpStatus) throws IOException {
|
||||
check("httpStatus").that(actual.execute().code()).isEqualTo(expectedHttpStatus);
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.apache.fineract.integrationtests.newstyle;
|
||||
|
||||
import com.google.common.truth.BigDecimalSubject;
|
||||
import com.google.common.truth.BooleanSubject;
|
||||
import com.google.common.truth.ComparableSubject;
|
||||
import com.google.common.truth.DoubleSubject;
|
||||
import com.google.common.truth.FloatSubject;
|
||||
import com.google.common.truth.IntegerSubject;
|
||||
import com.google.common.truth.IterableSubject;
|
||||
import com.google.common.truth.LongSubject;
|
||||
import com.google.common.truth.OptionalSubject;
|
||||
import com.google.common.truth.StringSubject;
|
||||
import com.google.common.truth.Subject;
|
||||
import com.google.common.truth.Truth;
|
||||
import com.google.common.truth.Truth8;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||
import org.apache.fineract.client.testutil.CallSubject;
|
||||
import org.apache.fineract.client.util.Calls;
|
||||
import org.apache.fineract.client.util.FineractClient;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import retrofit2.Call;
|
||||
|
||||
/**
|
||||
* Integration Test for /documents API.
|
||||
*
|
||||
* @author Michael Vorburger.ch
|
||||
*/
|
||||
// TODO Remove @TestMethodOrder when https://github.com/junit-team/junit5/issues/1919 is available
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public abstract class IntegrationTest {
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
private FineractClient fineract;
|
||||
|
||||
protected FineractClient fineract() {
|
||||
if (fineract == null) {
|
||||
// TODO change from Fineract.dev to https://localhost:8443/fineract-provider/api/v1/ after FINERACT-1209
|
||||
String url = System.getProperty("fineract.it.url", "https://demo.fineract.dev/fineract-provider/api/v1/");
|
||||
fineract = FineractClient.builder().baseURL(url).tenant("default").basicAuth("mifos", "password").insecure(true)
|
||||
.logging(Level.BODY).build();
|
||||
}
|
||||
return fineract;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link FineractClient#DATE_FORMAT}.
|
||||
*/
|
||||
protected String dateFormat() {
|
||||
return FineractClient.DATE_FORMAT;
|
||||
}
|
||||
|
||||
protected String random() {
|
||||
return Long.toString(random.nextLong());
|
||||
}
|
||||
|
||||
// This method just makes it easier to use Calls.ok() in tests (it avoids having to static import)
|
||||
protected <T> T ok(Call<T> call) {
|
||||
return Calls.ok(call);
|
||||
}
|
||||
|
||||
// as above, avoids import static CallSubject.assertThat
|
||||
protected <T> CallSubject assertThat(Call<T> call) {
|
||||
return CallSubject.assertThat(call);
|
||||
}
|
||||
|
||||
// as above, this avoids issues with e.g. the Eclipse compiler getting confused which assertThat is which
|
||||
public static IterableSubject assertThat(Iterable<?> actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static <T extends Comparable<?>> ComparableSubject<T> assertThat(T actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static BigDecimalSubject assertThat(BigDecimal actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static Subject assertThat(Object actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static LongSubject assertThat(Long actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static DoubleSubject assertThat(Double actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static FloatSubject assertThat(Float actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static IntegerSubject assertThat(Integer actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static BooleanSubject assertThat(Boolean actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
public static StringSubject assertThat(String actual) {
|
||||
return Truth.assertThat(actual);
|
||||
}
|
||||
|
||||
// from truth-java8-extension
|
||||
public static OptionalSubject assertThat(Optional<?> actual) {
|
||||
return Truth8.assertThat(actual);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.apache.fineract.integrationtests.newstyle;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.client.models.PostOfficesRequest;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Integration Test for /offices API.
|
||||
*
|
||||
* @author Michael Vorburger.ch
|
||||
*/
|
||||
public class OfficeTest extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void createOne() {
|
||||
// NB parentId(1) always exists (Head Office)
|
||||
// NB name random() because Office Names have to be unique
|
||||
// TODO requiring dateFormat(..).locale(..) is dumb :( see https://issues.apache.org/jira/browse/FINERACT-1233
|
||||
assertThat(ok(fineract().offices.createOffice(new PostOfficesRequest().name("TestOffice-" + random()).parentId(1L)
|
||||
.openingDate(LocalDate.now()).dateFormat(dateFormat()).locale("en_US"))).getOfficeId()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void retrieveOneExisting() {
|
||||
assertThat(ok(fineract().offices.retrieveOffices(true, null, null)).size()).isAtLeast(2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user