- refactored the tests

- moved some dto classes into common module
This commit is contained in:
Main
2016-08-09 22:43:41 +03:00
parent f1d97ac49c
commit 39309f23a1
40 changed files with 323 additions and 434 deletions

View File

@@ -1,7 +1,7 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web; package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountRequest; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountResponse; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;

View File

@@ -1,6 +1,8 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.accounts.AccountService;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;

View File

@@ -1,5 +1,7 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import java.util.List; import java.util.List;
/** /**

View File

@@ -1,6 +1,7 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts;
import com.mongodb.WriteResult; import com.mongodb.WriteResult;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;

View File

@@ -8,6 +8,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accoun
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountOpenedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountOpenedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.MoneyTransferCreatedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -1,6 +1,6 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web; package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.GetAccountResponse;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;

View File

@@ -4,7 +4,8 @@ import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.acc
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountNotFoundException; import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountNotFoundException;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountQueryService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountQueryService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.GetAccountResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;

View File

@@ -7,7 +7,7 @@ dependencies {
testCompile project(":accounts-query-side-backend") testCompile project(":accounts-query-side-backend")
testCompile project(":customers-command-side-backend") testCompile project(":customers-command-side-backend")
testCompile project(":customers-query-side-backend") testCompile project(":customers-query-side-backend")
testCompile project(":testutil-customers") testCompile project(":testutil")
testCompile "junit:junit:4.11" testCompile "junit:junit:4.11"
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion" testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion" testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"

View File

@@ -2,7 +2,7 @@ apply plugin: 'java'
dependencies { dependencies {
compile project(":common-auth") compile project(":common-auth")
compile project(":common-customers") compile project(":common")
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion" compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
compile "org.springframework.boot:spring-boot-starter-security:$springBootVersion" compile "org.springframework.boot:spring-boot-starter-security:$springBootVersion"

View File

@@ -1,7 +1,7 @@
apply plugin: 'java' apply plugin: 'java'
dependencies { dependencies {
compile project(":common-customers") compile project(":common")
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion" compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
compile "org.springframework.boot:spring-boot-starter-data-mongodb:$springBootVersion" compile "org.springframework.boot:spring-boot-starter-data-mongodb:$springBootVersion"

View File

@@ -1,7 +1,7 @@
apply plugin: 'java' apply plugin: 'java'
dependencies { dependencies {
compile project(":common-customers") compile project(":common")
compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion" compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion"

View File

@@ -1,4 +1,4 @@
package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.HashCodeBuilder;

View File

@@ -1,8 +1,7 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.DecimalMin; import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
public class CreateAccountRequest { public class CreateAccountRequest {

View File

@@ -1,4 +1,4 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
public class CreateAccountResponse { public class CreateAccountResponse {

View File

@@ -1,4 +1,4 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts; package net.chrisrichardson.eventstore.javaexamples.banking.common.accounts;
import java.math.BigDecimal; import java.math.BigDecimal;

View File

@@ -1,8 +1,8 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions; package net.chrisrichardson.eventstore.javaexamples.banking.common.transactions;
import java.math.BigDecimal;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.DecimalMin; import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
public class CreateMoneyTransferRequest { public class CreateMoneyTransferRequest {

View File

@@ -1,4 +1,4 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions; package net.chrisrichardson.eventstore.javaexamples.banking.common.transactions;
public class CreateMoneyTransferResponse { public class CreateMoneyTransferResponse {

View File

@@ -1,11 +1,11 @@
apply plugin: 'java' apply plugin: 'java'
dependencies { dependencies {
compile project(":common-customers") compile project(":common")
compile project(":common-backend") compile project(":common-backend")
compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion" compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion"
testCompile project(":testutil-customers") testCompile project(":testutil")
testCompile "junit:junit:4.11" testCompile "junit:junit:4.11"
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion" testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion" testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"

View File

@@ -12,6 +12,6 @@ dependencies {
compile "io.eventuate.client.java:eventuate-client-java-http-stomp-spring:$eventuateClientVersion" compile "io.eventuate.client.java:eventuate-client-java-http-stomp-spring:$eventuateClientVersion"
testCompile project(":testutil-customers") testCompile project(":testutil")
testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.springframework.boot:spring-boot-starter-test"
} }

View File

@@ -1,7 +1,7 @@
apply plugin: 'java' apply plugin: 'java'
dependencies { dependencies {
compile project(":common-customers") compile project(":common")
compile project(":customers-command-side-backend") compile project(":customers-command-side-backend")
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion" compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"

View File

@@ -12,7 +12,7 @@ dependencies {
compile "io.eventuate.client.java:eventuate-client-java-http-stomp-spring:$eventuateClientVersion" compile "io.eventuate.client.java:eventuate-client-java-http-stomp-spring:$eventuateClientVersion"
testCompile project(":testutil-customers") testCompile project(":testutil")
testCompile project(":customers-command-side-service") testCompile project(":customers-command-side-service")
testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.springframework.boot:spring-boot-starter-test"
} }

View File

@@ -5,7 +5,7 @@ dependencies {
testCompile project(":transactions-command-side-web") testCompile project(":transactions-command-side-web")
testCompile project(":accounts-query-side-web") testCompile project(":accounts-query-side-web")
testCompile project(":testutil-customers") testCompile project(":testutil")
testCompile project(":common-auth") testCompile project(":common-auth")
testCompile "junit:junit:4.11" testCompile "junit:junit:4.11"
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion" testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"

View File

@@ -1,187 +1,31 @@
package net.chrisrichardson.eventstore.examples.bank.web; package net.chrisrichardson.eventstore.examples.bank.web;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstorestore.javaexamples.testutil.AbstractRestAPITest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo; import net.chrisrichardson.eventstorestore.javaexamples.testutil.AuthenticatedRestTemplate;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils.BasicAuthUtils;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal; public class EndToEndTest extends AbstractRestAPITest {
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually; private String getenv(String name, String defaultValue) {
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateCustomerInfo; String x = System.getenv(name);
import static org.junit.Assert.assertTrue; return x == null ? defaultValue : x;
}
public class EndToEndTest { public String baseUrl(String path) {
return "http://" + getenv("SERVICE_HOST", "localhost") + ":" + 8080 + "/" + path;
}
private String getenv(String name, String defaultValue) { RestTemplate restTemplate = new RestTemplate();
String x = System.getenv(name);
return x == null ? defaultValue : x;
}
private String makeBaseUrl(int port, String path) { @Override
return "http://" + getenv("SERVICE_HOST", "localhost") + ":" + port + "/" + path; public AuthenticatedRestTemplate getAuthenticatedRestTemplate() {
} return new AuthenticatedRestTemplate(restTemplate);
}
private String accountsCommandSideBaseUrl(String path) { @Override
return makeBaseUrl(8080, path); public RestTemplate getRestTemplate() {
} return restTemplate;
private String accountsQuerySideBaseUrl(String path) { }
return makeBaseUrl(8081, path);
}
private String transactionsCommandSideBaseUrl(String path) {
return makeBaseUrl(8082, path);
}
private String customersCommandSideBaseUrl(String path) {
return makeBaseUrl(8083, path);
}
private String customersQuerySideBaseUrl(String path) {
return makeBaseUrl(8084, path);
}
RestTemplate restTemplate = new RestTemplate();
CustomersTestUtils customersTestUtils = new CustomersTestUtils(restTemplate, customersQuerySideBaseUrl("/customers/"));
@Test
public void shouldCreateCustomerAndAccountsAndTransferMoney() {
CustomerInfo customerInfo = generateCustomerInfo();
BigDecimal initialFromAccountBalance = new BigDecimal(500);
BigDecimal initialToAccountBalance = new BigDecimal(100);
BigDecimal amountToTransfer = new BigDecimal(150);
BigDecimal finalFromAccountBalance = initialFromAccountBalance.subtract(amountToTransfer);
BigDecimal finalToAccountBalance = initialToAccountBalance.add(amountToTransfer);
final CustomerResponse customerResponse = restTemplate.postForEntity(customersCommandSideBaseUrl("/customers"),customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
customersTestUtils.assertCustomerResponse(customerId, customerInfo);
final CreateAccountResponse fromAccount = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
accountsCommandSideBaseUrl("/accounts"),
HttpMethod.POST,
CreateAccountResponse.class,
new CreateAccountRequest(customerId, "My #1 Account", "", initialFromAccountBalance)
);
final String fromAccountId = fromAccount.getAccountId();
CreateAccountResponse toAccount = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
accountsCommandSideBaseUrl("/accounts"),
HttpMethod.POST,
CreateAccountResponse.class,
new CreateAccountRequest(customerId, "My #2 Account", "", initialToAccountBalance)
);
String toAccountId = toAccount.getAccountId();
Assert.assertNotNull(fromAccountId);
Assert.assertNotNull(toAccountId);
assertAccountBalance(fromAccountId, initialFromAccountBalance);
assertAccountBalance(toAccountId, initialToAccountBalance);
final CreateMoneyTransferResponse moneyTransfer = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
transactionsCommandSideBaseUrl("/transfers"),
HttpMethod.POST,
CreateMoneyTransferResponse.class,
new CreateMoneyTransferRequest(fromAccountId, toAccountId, amountToTransfer, "")
);
assertAccountBalance(fromAccountId, finalFromAccountBalance);
assertAccountBalance(toAccountId, finalToAccountBalance);
// TOOD - check state of money transfer
List<AccountTransactionInfo> transactionInfoList = restTemplate.exchange(accountsQuerySideBaseUrl("/accounts/"+fromAccountId+"/history"),
HttpMethod.GET,
new HttpEntity(BasicAuthUtils.basicAuthHeaders("test_user@mail.com")),
new ParameterizedTypeReference<List<AccountTransactionInfo>>() {}).getBody();
assertTrue(transactionInfoList.stream().filter(ti -> ti.getTransactionId().equals(moneyTransfer.getMoneyTransferId()) &&
ti.getFromAccountId().equals(fromAccountId) &&
ti.getToAccountId().equals(toAccountId) &&
ti.getAmount() == toCents(amountToTransfer).longValue()).findFirst().isPresent());
}
@Test
public void shouldCreateAccountsAndGetByCustomer() {
BigDecimal initialFromAccountBalance = new BigDecimal(500);
CustomerInfo customerInfo = generateCustomerInfo();
final CustomerResponse customerResponse = restTemplate.postForEntity(customersCommandSideBaseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
Assert.assertNotNull(customerId);
Assert.assertEquals(customerInfo, customerResponse.getCustomerInfo());
customersTestUtils.assertCustomerResponse(customerId, customerInfo);
final CreateAccountResponse account = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
accountsCommandSideBaseUrl("/accounts"),
HttpMethod.POST,
CreateAccountResponse.class,
new CreateAccountRequest(customerId, "My 1 Account", "", initialFromAccountBalance)
);
final String accountId = account.getAccountId();
Assert.assertNotNull(accountId);
assertAccountBalance(accountId, initialFromAccountBalance);
List<GetAccountResponse> accountResponseList = restTemplate.exchange(accountsQuerySideBaseUrl("/accounts?customerId="+customerId),
HttpMethod.GET,
new HttpEntity(BasicAuthUtils.basicAuthHeaders("test_user@mail.com")),
new ParameterizedTypeReference<List<GetAccountResponse>>() {}).getBody();
assertTrue(accountResponseList.stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent());
}
private BigDecimal toCents(BigDecimal dollarAmount) {
return dollarAmount.multiply(new BigDecimal(100));
}
private void assertAccountBalance(final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
final BigDecimal inCents = toCents(expectedBalanceInDollars);
eventually(
new Producer<GetAccountResponse>() {
@Override
public CompletableFuture<GetAccountResponse> produce() {
return CompletableFuture.completedFuture(BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
accountsQuerySideBaseUrl("/accounts/" + fromAccountId),
HttpMethod.GET,
GetAccountResponse.class));
}
},
new Verifier<GetAccountResponse>() {
@Override
public void verify(GetAccountResponse accountInfo) {
Assert.assertEquals(fromAccountId, accountInfo.getAccountId());
Assert.assertEquals(inCents, accountInfo.getBalance());
}
});
}
} }

View File

@@ -16,7 +16,7 @@ dependencies {
compile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion" compile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"
testCompile project(":testutil-customers") testCompile project(":testutil")
testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.springframework.boot:spring-boot-starter-test"
} }

View File

@@ -1,216 +1,40 @@
package net.chrisrichardson.eventstore.javaexamples.banking.web; package net.chrisrichardson.eventstore.javaexamples.banking.web;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.accounts.AccountTransactionInfo; import net.chrisrichardson.eventstorestore.javaexamples.testutil.AbstractRestAPITest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.*; import net.chrisrichardson.eventstorestore.javaexamples.testutil.AuthenticatedRestTemplate;
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils.BasicAuthUtils;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.accounts.CreateAccountResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.transactions.CreateMoneyTransferResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.web.queryside.accounts.GetAccountResponse;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateCustomerInfo;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.customers.CustomersTestUtils.generateToAccountInfo;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BankingWebTestConfiguration.class) @SpringApplicationConfiguration(classes = BankingWebTestConfiguration.class)
@WebAppConfiguration @WebAppConfiguration
@IntegrationTest({"server.port=0", "management.port=0"}) @IntegrationTest({"server.port=0", "management.port=0"})
public class BankingWebIntegrationTest { public class BankingWebIntegrationTest extends AbstractRestAPITest {
@Value("${local.server.port}") @Value("${local.server.port}")
private int port; private int port;
private String baseUrl(String path) { @Override
public String baseUrl(String path) {
return "http://localhost:" + port + "/" + path; return "http://localhost:" + port + "/" + path;
} }
@Autowired @Autowired
RestTemplate restTemplate; RestTemplate restTemplate;
CustomersTestUtils customersTestUtils; @Override
public AuthenticatedRestTemplate getAuthenticatedRestTemplate() {
@PostConstruct return new AuthenticatedRestTemplate(restTemplate);
private void init() {
customersTestUtils = new CustomersTestUtils(restTemplate, baseUrl("/customers/"));
} }
@Override
@Test public RestTemplate getRestTemplate() {
public void shouldCreateAccountsAndTransferMoney() { return restTemplate;
BigDecimal initialFromAccountBalance = new BigDecimal(500);
BigDecimal initialToAccountBalance = new BigDecimal(100);
BigDecimal amountToTransfer = new BigDecimal(150);
BigDecimal finalFromAccountBalance = initialFromAccountBalance.subtract(amountToTransfer);
BigDecimal finalToAccountBalance = initialToAccountBalance.add(amountToTransfer);
final CreateAccountResponse fromAccount = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/accounts"),
HttpMethod.POST,
CreateAccountResponse.class,
new CreateAccountRequest("00000000-00000000", "My 1 Account", "", initialFromAccountBalance)
);
final String fromAccountId = fromAccount.getAccountId();
CreateAccountResponse toAccount = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/accounts"),
HttpMethod.POST,
CreateAccountResponse.class,
new CreateAccountRequest("00000000-00000000", "My 2 Account", "", initialToAccountBalance)
);
String toAccountId = toAccount.getAccountId();
Assert.assertNotNull(fromAccountId);
Assert.assertNotNull(toAccountId);
assertAccountBalance(fromAccountId, initialFromAccountBalance);
assertAccountBalance(toAccountId, initialToAccountBalance);
final CreateMoneyTransferResponse moneyTransfer = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/transfers"),
HttpMethod.POST,
CreateMoneyTransferResponse.class,
new CreateMoneyTransferRequest(fromAccountId, toAccountId, amountToTransfer, "")
);
assertAccountBalance(fromAccountId, finalFromAccountBalance);
assertAccountBalance(toAccountId, finalToAccountBalance);
List<AccountTransactionInfo> transactionInfoList = restTemplate.exchange(baseUrl("/accounts/"+fromAccountId+"/history"),
HttpMethod.GET,
new HttpEntity(BasicAuthUtils.basicAuthHeaders("test_user@mail.com")),
new ParameterizedTypeReference<List<AccountTransactionInfo>>() {}).getBody();
assertTrue(transactionInfoList.stream().filter(ti -> ti.getTransactionId().equals(moneyTransfer.getMoneyTransferId()) &&
ti.getFromAccountId().equals(fromAccountId) &&
ti.getToAccountId().equals(toAccountId) &&
ti.getAmount() == toCents(amountToTransfer).longValue()).findFirst().isPresent());
}
@Test
public void shouldCreateAccountsAndGetByCustomer() {
BigDecimal initialFromAccountBalance = new BigDecimal(500);
CustomerInfo customerInfo = generateCustomerInfo();
final CustomerResponse customerResponse = restTemplate.postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
Assert.assertNotNull(customerId);
Assert.assertEquals(customerInfo, customerResponse.getCustomerInfo());
customersTestUtils.assertCustomerResponse(customerId, customerInfo);
final CreateAccountResponse account = BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/accounts"),
HttpMethod.POST,
CreateAccountResponse.class,
new CreateAccountRequest(customerId, "My 1 Account", "", initialFromAccountBalance)
);
final String accountId = account.getAccountId();
Assert.assertNotNull(accountId);
assertAccountBalance(accountId, initialFromAccountBalance);
List<GetAccountResponse> accountResponseList = restTemplate.exchange(baseUrl("/accounts?customerId="+customerId),
HttpMethod.GET,
new HttpEntity(BasicAuthUtils.basicAuthHeaders("test_user@mail.com")),
new ParameterizedTypeReference<List<GetAccountResponse>>() {}).getBody();
assertTrue(accountResponseList.stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent());
}
@Test
public void shouldCreateCustomersAndAddToAccount() {
CustomerInfo customerInfo = generateCustomerInfo();
final CustomerResponse customerResponse = restTemplate.postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
Assert.assertNotNull(customerId);
Assert.assertEquals(customerInfo, customerResponse.getCustomerInfo());
customersTestUtils.assertCustomerResponse(customerId, customerInfo);
ToAccountInfo toAccountInfo = generateToAccountInfo();
BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/customers/"+customerId+"/toaccounts"),
HttpMethod.POST,
null,
toAccountInfo
);
assertToAccountsContains(customerId, toAccountInfo);
}
private BigDecimal toCents(BigDecimal dollarAmount) {
return dollarAmount.multiply(new BigDecimal(100));
}
private void assertAccountBalance(final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
final BigDecimal inCents = toCents(expectedBalanceInDollars);
eventually(
new Producer<GetAccountResponse>() {
@Override
public CompletableFuture<GetAccountResponse> produce() {
return CompletableFuture.completedFuture(BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/accounts/" + fromAccountId),
HttpMethod.GET,
GetAccountResponse.class));
}
},
new Verifier<GetAccountResponse>() {
@Override
public void verify(GetAccountResponse accountInfo) {
Assert.assertEquals(fromAccountId, accountInfo.getAccountId());
Assert.assertEquals(inCents, accountInfo.getBalance());
}
});
}
private void assertToAccountsContains(final String customerId, final ToAccountInfo toAccountInfo) {
eventually(
new Producer<QuerySideCustomer>() {
@Override
public CompletableFuture<QuerySideCustomer> produce() {
return CompletableFuture.completedFuture(BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
baseUrl("/customers/" + customerId),
HttpMethod.GET,
QuerySideCustomer.class));
}
},
new Verifier<QuerySideCustomer>() {
@Override
public void verify(QuerySideCustomer customerResponse) {
Assert.assertEquals(customerId, customerResponse.getId());
assertTrue(customerResponse.getToAccounts().values().stream().anyMatch(t -> t.equals(toAccountInfo)));
}
});
} }
} }

View File

@@ -1,37 +1,35 @@
include 'testutil' include 'testutil'
include 'common'
include 'common-backend'
include 'common-auth'
include 'common-auth-web'
include 'common-swagger' include 'common-swagger'
include 'common-backend'
include 'accounts-command-side-backend' include 'accounts-command-side-backend'
include 'transactions-command-side-backend'
include 'accounts-command-side-web' include 'accounts-command-side-web'
include 'transactions-command-side-web' include 'accounts-command-side-service'
include 'accounts-query-side-backend' include 'accounts-query-side-backend'
include 'accounts-query-side-web' include 'accounts-query-side-web'
include 'accounts-query-side-service'
include 'backend-integration-tests' include 'transactions-command-side-backend'
include 'transactions-command-side-web'
include 'transactions-command-side-service'
include 'customers-command-side-backend'
include 'customers-command-side-web'
include 'customers-command-side-service'
include 'customers-query-side-backend'
include 'customers-query-side-web'
include 'customers-query-side-service'
include 'api-gateway-service'
include 'monolithic-service' include 'monolithic-service'
include 'accounts-command-side-service' include 'backend-integration-tests'
include 'accounts-query-side-service'
include 'transactions-command-side-service'
include 'e2e-test' include 'e2e-test'
rootProject.name = 'java-spring-event-sourcing-example' rootProject.name = 'java-spring-event-sourcing-example'
include 'common-auth'
include 'customers-command-side-backend'
include 'customers-command-side-web'
include 'customers-query-side-backend'
include 'customers-query-side-web'
include 'common-customers'
include 'customers-command-side-service'
include 'customers-query-side-service'
include 'common-auth-web'
include 'api-gateway-service'
include 'testutil-customers'

View File

@@ -1,10 +0,0 @@
apply plugin: 'java'
dependencies {
compile project(":testutil")
compile project(":common-auth")
compile project(":common-customers")
compile "io.reactivex:rxjava:1.1.5"
compile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
}

View File

@@ -1,13 +1,12 @@
apply plugin: 'java' apply plugin: 'java'
dependencies { dependencies {
compile project(":common")
compile project(":common-auth")
compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion" compile "io.eventuate.client.java:eventuate-client-java-spring:$eventuateClientVersion"
compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
compile "junit:junit:4.11" compile "junit:junit:4.11"
compile "io.reactivex:rxjava:1.1.5" compile "io.reactivex:rxjava:1.1.5"
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
testCompile "io.eventuate.client.java:eventuate-client-java-jdbc:$eventuateClientVersion"
} }

View File

@@ -0,0 +1,202 @@
package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.CreateAccountResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.GetAccountResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.CustomerResponse;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.QuerySideCustomer;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.CreateMoneyTransferRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.CreateMoneyTransferResponse;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateCustomerInfo;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.CustomersTestUtils.generateToAccountInfo;
import static net.chrisrichardson.eventstorestore.javaexamples.testutil.TestUtil.eventually;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public abstract class AbstractRestAPITest {
@Test
public void shouldCreateAccountsAndTransferMoney() {
BigDecimal initialFromAccountBalance = new BigDecimal(500);
BigDecimal initialToAccountBalance = new BigDecimal(100);
BigDecimal amountToTransfer = new BigDecimal(150);
BigDecimal finalFromAccountBalance = initialFromAccountBalance.subtract(amountToTransfer);
BigDecimal finalToAccountBalance = initialToAccountBalance.add(amountToTransfer);
final CreateAccountResponse fromAccount = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
new CreateAccountRequest("00000000-00000000", "My 1 Account", "", initialFromAccountBalance),
CreateAccountResponse.class);
final String fromAccountId = fromAccount.getAccountId();
CreateAccountResponse toAccount = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
new CreateAccountRequest("00000000-00000000", "My 2 Account", "", initialToAccountBalance),
CreateAccountResponse.class);
String toAccountId = toAccount.getAccountId();
Assert.assertNotNull(fromAccountId);
Assert.assertNotNull(toAccountId);
assertAccountBalance(fromAccountId, initialFromAccountBalance);
assertAccountBalance(toAccountId, initialToAccountBalance);
final CreateMoneyTransferResponse moneyTransfer = getAuthenticatedRestTemplate().postForEntity(baseUrl("/transfers"),
new CreateMoneyTransferRequest(fromAccountId, toAccountId, amountToTransfer, ""),
CreateMoneyTransferResponse.class);
assertAccountBalance(fromAccountId, finalFromAccountBalance);
assertAccountBalance(toAccountId, finalToAccountBalance);
eventually(
new Producer<AccountTransactionInfo[]>() {
@Override
public CompletableFuture<AccountTransactionInfo[]> produce() {
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts/" + fromAccountId + "/history"),
AccountTransactionInfo[].class));
}
},
new Verifier<AccountTransactionInfo[]>() {
@Override
public void verify(AccountTransactionInfo[] transactionInfos) {
Optional<AccountTransactionInfo> first = Arrays.asList(transactionInfos).stream().filter(ti -> ti.getTransactionId().equals(moneyTransfer.getMoneyTransferId())).findFirst();
assertTrue(first.isPresent());
AccountTransactionInfo ti = first.get();
assertEquals(fromAccountId, ti.getFromAccountId());
assertEquals(toAccountId, ti.getToAccountId());
assertEquals(toAccountId, ti.getToAccountId());
assertEquals(fromAccountId, ti.getFromAccountId());
assertEquals(toCents(amountToTransfer).longValue(), ti.getAmount());
}
});
}
@Test
public void shouldCreateAccountsAndGetByCustomer() {
BigDecimal initialFromAccountBalance = new BigDecimal(500);
CustomerInfo customerInfo = generateCustomerInfo();
final CustomerResponse customerResponse = getRestTemplate().postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
Assert.assertNotNull(customerId);
assertEquals(customerInfo, customerResponse.getCustomerInfo());
getCustomersTestUtils().assertCustomerResponse(customerId, customerInfo);
final CreateAccountResponse account = getAuthenticatedRestTemplate().postForEntity(baseUrl("/accounts"),
new CreateAccountRequest(customerId, "My 1 Account", "", initialFromAccountBalance),
CreateAccountResponse.class);
final String accountId = account.getAccountId();
Assert.assertNotNull(accountId);
assertAccountBalance(accountId, initialFromAccountBalance);
eventually(
new Producer<GetAccountResponse[]>() {
@Override
public CompletableFuture<GetAccountResponse[]> produce() {
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts?customerId=" + customerId),
GetAccountResponse[].class));
}
},
new Verifier<GetAccountResponse[]>() {
@Override
public void verify(GetAccountResponse[] accountResponses) {
assertTrue(Arrays.asList(accountResponses).stream().filter(acc -> acc.getAccountId().equals(accountId)).findFirst().isPresent());
}
});
}
@Test
public void shouldCreateCustomersAndAddToAccount() {
CustomerInfo customerInfo = generateCustomerInfo();
final CustomerResponse customerResponse = getRestTemplate().postForEntity(baseUrl("/customers"), customerInfo, CustomerResponse.class).getBody();
final String customerId = customerResponse.getId();
Assert.assertNotNull(customerId);
assertEquals(customerInfo, customerResponse.getCustomerInfo());
getCustomersTestUtils().assertCustomerResponse(customerId, customerInfo);
ToAccountInfo toAccountInfo = generateToAccountInfo();
getAuthenticatedRestTemplate().postForEntity(baseUrl("/customers/" + customerId + "/toaccounts"),
toAccountInfo,
null);
assertToAccountsContains(customerId, toAccountInfo);
}
private BigDecimal toCents(BigDecimal dollarAmount) {
return dollarAmount.multiply(new BigDecimal(100));
}
private void assertAccountBalance(final String fromAccountId, final BigDecimal expectedBalanceInDollars) {
final BigDecimal inCents = toCents(expectedBalanceInDollars);
eventually(
new Producer<GetAccountResponse>() {
@Override
public CompletableFuture<GetAccountResponse> produce() {
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/accounts/" + fromAccountId),
GetAccountResponse.class));
}
},
new Verifier<GetAccountResponse>() {
@Override
public void verify(GetAccountResponse accountInfo) {
assertEquals(fromAccountId, accountInfo.getAccountId());
assertEquals(inCents, accountInfo.getBalance());
}
});
}
private void assertToAccountsContains(final String customerId, final ToAccountInfo toAccountInfo) {
eventually(
new Producer<QuerySideCustomer>() {
@Override
public CompletableFuture<QuerySideCustomer> produce() {
return CompletableFuture.completedFuture(getAuthenticatedRestTemplate().getForEntity(baseUrl("/customers/" + customerId),
QuerySideCustomer.class));
}
},
new Verifier<QuerySideCustomer>() {
@Override
public void verify(QuerySideCustomer customerResponse) {
assertEquals(customerId, customerResponse.getId());
assertTrue(customerResponse.getToAccounts().values().stream().anyMatch(t -> t.equals(toAccountInfo)));
}
});
}
public abstract AuthenticatedRestTemplate getAuthenticatedRestTemplate();
public abstract RestTemplate getRestTemplate();
public abstract String baseUrl(String path);
public abstract CustomersTestUtils getCustomersTestUtils();
}

View File

@@ -0,0 +1,30 @@
package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils.BasicAuthUtils;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
public class AuthenticatedRestTemplate {
private RestTemplate restTemplate;
public AuthenticatedRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public <T> T getForEntity(String url, Class<T> clazz) {
return BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
url,
HttpMethod.GET,
clazz);
}
public <T> T postForEntity(String url, Object requestObject, Class<T> clazz) {
return BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate,
url,
HttpMethod.POST,
clazz,
requestObject
);
}
}

View File

@@ -1,11 +1,7 @@
package net.chrisrichardson.eventstorestore.javaexamples.testutil.customers; package net.chrisrichardson.eventstorestore.javaexamples.testutil;
import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.*; import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.*;
import net.chrisrichardson.eventstore.javaexamples.banking.commonauth.utils.BasicAuthUtils;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Producer;
import net.chrisrichardson.eventstorestore.javaexamples.testutil.Verifier;
import org.junit.Assert; import org.junit.Assert;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -26,14 +22,12 @@ public class CustomersTestUtils {
} }
public void assertCustomerResponse(final String customerId, final CustomerInfo customerInfo) { public void assertCustomerResponse(final String customerId, final CustomerInfo customerInfo) {
AuthenticatedRestTemplate art = new AuthenticatedRestTemplate(restTemplate);
eventually( eventually(
new Producer<QuerySideCustomer>() { new Producer<QuerySideCustomer>() {
@Override @Override
public CompletableFuture<QuerySideCustomer> produce() { public CompletableFuture<QuerySideCustomer> produce() {
return CompletableFuture.completedFuture(BasicAuthUtils.doBasicAuthenticatedRequest(restTemplate, return CompletableFuture.completedFuture(art.getForEntity(customersBaseUrl + customerId, QuerySideCustomer.class));
customersBaseUrl + customerId,
HttpMethod.GET,
QuerySideCustomer.class));
} }
}, },
new Verifier<QuerySideCustomer>() { new Verifier<QuerySideCustomer>() {
@@ -72,6 +66,6 @@ public class CustomersTestUtils {
} }
public static ToAccountInfo generateToAccountInfo() { public static ToAccountInfo generateToAccountInfo() {
return new ToAccountInfo("11111111-11111111", "New Account", "John Doe",""); return new ToAccountInfo("11111111-11111111", "New Account", "John Doe", "");
} }
} }

View File

@@ -3,6 +3,8 @@ package net.chrisrichardson.eventstore.javaexamples.banking.web.commandside.tran
import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService; import net.chrisrichardson.eventstore.javaexamples.banking.backend.commandside.transactions.MoneyTransferService;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails; import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.transactions.TransferDetails;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.CreateMoneyTransferRequest;
import net.chrisrichardson.eventstore.javaexamples.banking.common.transactions.CreateMoneyTransferResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;