Merge remote-tracking branch 'remotes/upstream/wip-eventuate-local' into wip-customer
This commit is contained in:
@@ -4,6 +4,7 @@ import com.mongodb.WriteResult;
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
@@ -38,6 +39,9 @@ public class AccountInfoUpdateService {
|
||||
Collections.<AccountTransactionInfo>emptyList(),
|
||||
version));
|
||||
logger.info("Saved in mongo");
|
||||
|
||||
} catch (DuplicateKeyException t) {
|
||||
logger.warn("When saving ", t);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Error during saving: ");
|
||||
logger.error("Error during saving: ", t);
|
||||
|
||||
@@ -94,4 +94,20 @@ public class AccountInfoUpdateServiceTest {
|
||||
assertEquals(ti, accountInfo.getTransactions().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleDuplicateSaveAccountInfo() throws ExecutionException, InterruptedException {
|
||||
IdGenerator x = new IdGeneratorImpl();
|
||||
String accountId = x.genId().asString();
|
||||
String customerId = x.genId().asString();
|
||||
String version = x.genId().asString();
|
||||
|
||||
String title = "Checking account";
|
||||
BigDecimal initialBalance = new BigDecimal("1345");
|
||||
String description = "Some account";
|
||||
|
||||
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
|
||||
accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Quer
|
||||
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -13,36 +14,38 @@ import java.util.Collections;
|
||||
*/
|
||||
public class CustomerInfoUpdateService {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private QuerySideCustomerRepository accountInfoRepository;
|
||||
private QuerySideCustomerRepository querySideCustomerRepository;
|
||||
|
||||
public CustomerInfoUpdateService(QuerySideCustomerRepository accountInfoRepository) {
|
||||
this.accountInfoRepository = accountInfoRepository;
|
||||
}
|
||||
|
||||
public void create(String id, CustomerInfo customerInfo) {
|
||||
try {
|
||||
accountInfoRepository.save(new QuerySideCustomer(id,
|
||||
customerInfo.getName(),
|
||||
customerInfo.getEmail(),
|
||||
customerInfo.getSsn(),
|
||||
customerInfo.getPhoneNumber(),
|
||||
customerInfo.getAddress(),
|
||||
Collections.<String, ToAccountInfo>emptyMap()
|
||||
)
|
||||
);
|
||||
logger.info("Saved in mongo");
|
||||
} catch (Throwable t) {
|
||||
logger.error("Error during saving: ", t);
|
||||
throw new RuntimeException(t);
|
||||
public CustomerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) {
|
||||
this.querySideCustomerRepository = querySideCustomerRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public void addToAccount(String id, ToAccountInfo accountInfo) {
|
||||
QuerySideCustomer customer = accountInfoRepository.findOne(id);
|
||||
customer.getToAccounts().put(accountInfo.getId(), accountInfo);
|
||||
accountInfoRepository.save(customer);
|
||||
}
|
||||
public void create(String id, CustomerInfo customerInfo) {
|
||||
try {
|
||||
querySideCustomerRepository.save(new QuerySideCustomer(id,
|
||||
customerInfo.getName(),
|
||||
customerInfo.getEmail(),
|
||||
customerInfo.getSsn(),
|
||||
customerInfo.getPhoneNumber(),
|
||||
customerInfo.getAddress(),
|
||||
Collections.<String, ToAccountInfo>emptyMap()
|
||||
)
|
||||
);
|
||||
logger.info("Saved in mongo");
|
||||
} catch (DuplicateKeyException t) {
|
||||
logger.warn("When saving ", t);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Error during saving: ", t);
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void addToAccount(String id, ToAccountInfo accountInfo) {
|
||||
QuerySideCustomer customer = querySideCustomerRepository.findOne(id);
|
||||
customer.getToAccounts().put(accountInfo.getId(), accountInfo);
|
||||
querySideCustomerRepository.save(customer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package net.chrisrichardson.eventstorestore.javaexamples.testutil;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
import rx.functions.Action1;
|
||||
@@ -13,7 +11,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class TestUtil {
|
||||
|
||||
@@ -25,18 +22,6 @@ public class TestUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T awaitSuccessfulRequest(Supplier<ResponseEntity<T>> func, Func1<T, Boolean> predicate) {
|
||||
try {
|
||||
return Observable.interval(400, TimeUnit.MILLISECONDS)
|
||||
.take(50)
|
||||
.map(x -> func.get())
|
||||
.filter(re -> re.getStatusCode().equals(HttpStatus.OK) && re.getBody() != null && predicate.call(re.getBody()))
|
||||
.toBlocking().first().getBody();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Tuple2<A, B> {
|
||||
private A first;
|
||||
@@ -52,7 +37,7 @@ public class TestUtil {
|
||||
|
||||
}
|
||||
|
||||
static class Success<T> implements Outcome<T> {
|
||||
static class Success<T> implements Outcome<T> {
|
||||
|
||||
T value;
|
||||
|
||||
@@ -69,51 +54,26 @@ public class TestUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void eventually(final Producer<T> producer, final Verifier<T> verifier) {
|
||||
final int n = 150;
|
||||
Object possibleException = Observable.timer(0, 200, TimeUnit.MILLISECONDS).flatMap(new Func1<Long, Observable<Outcome<T>>>() {
|
||||
|
||||
@Override
|
||||
public Observable<Outcome<T>> call(Long aLong) {
|
||||
try {
|
||||
return fromCompletableFuture(producer.produce()).map(new Func1<T, Outcome<T>>() {
|
||||
@Override
|
||||
public Outcome<T> call(T t) {
|
||||
return new Success<T>(t);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Outcome<T> value = new Failure<T>(e);
|
||||
return Observable.just(value);
|
||||
}
|
||||
public static <T> void eventually(Producer<T> producer, Verifier<T> predicate) {
|
||||
Throwable laste = null;
|
||||
for (int i = 0; i < 30 ; i++) {
|
||||
try {
|
||||
T x = producer.produce().get(30, TimeUnit.SECONDS);
|
||||
predicate.verify(x);
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
laste = t;
|
||||
}
|
||||
}).map(new Func1<Outcome<T>, Throwable>() {
|
||||
@Override
|
||||
public Throwable call(Outcome<T> t) {
|
||||
try {
|
||||
if (t instanceof Success) {
|
||||
verifier.verify(((Success<T>) t).value);
|
||||
return null;
|
||||
} else
|
||||
return ((Failure<T>) t).t;
|
||||
} catch (Throwable e) {
|
||||
return e;
|
||||
}
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).take(n).zipWith(Observable.range(0, n), new Func2<Throwable, Integer, Tuple2<Throwable, Integer>>() {
|
||||
@Override
|
||||
public Tuple2<Throwable, Integer> call(Throwable e, Integer idx) {
|
||||
return new Tuple2<Throwable, Integer>(e, idx);
|
||||
}
|
||||
}).skipWhile(new Func1<Tuple2<Throwable, Integer>, Boolean>() {
|
||||
@Override
|
||||
public Boolean call(Tuple2<Throwable, Integer> tuple2) {
|
||||
return tuple2.first != null && tuple2.second < n - 1;
|
||||
}
|
||||
}).first().toBlocking().getIterator().next().first;
|
||||
|
||||
if (possibleException != null)
|
||||
throw new RuntimeException((Throwable) possibleException);
|
||||
}
|
||||
if (laste != null)
|
||||
throw new RuntimeException("Last exception was", laste);
|
||||
else
|
||||
throw new RuntimeException("predicate never satisfied");
|
||||
}
|
||||
|
||||
private static <T> Observable<T> fromCompletableFuture(CompletableFuture<T> future) {
|
||||
|
||||
Reference in New Issue
Block a user