From 19df48f33ccffc5dde4f641f0eea7c1381c0f6de Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Wed, 17 Oct 2018 13:13:13 +0300 Subject: [PATCH 1/4] NY_3810: Implement search user by attributes --- pom.xml | 37 ++++- .../GrpcServerHealthIndicator.java | 10 +- .../biz/nynja/search/models/AccountInfo.java | 72 --------- .../repositories/AccountInfoRepository.java | 18 --- .../services/AccountServiceCommunicator.java | 80 ++++++++++ .../search/services/AccountServiceImpl.java | 56 ------- .../search/services/SearchServiceImpl.java | 143 ++++++++++++++++++ src/main/resources/application-dev.yml | 12 +- src/main/resources/application-production.yml | 7 - src/main/resources/logback-spring.groovy | 9 +- .../biz/nynja/search/ApplicationTests.java | 27 ++-- src/test/java/biz/nynja/search/Util.java | 36 ++--- 12 files changed, 311 insertions(+), 196 deletions(-) delete mode 100644 src/main/java/biz/nynja/search/models/AccountInfo.java delete mode 100644 src/main/java/biz/nynja/search/repositories/AccountInfoRepository.java create mode 100644 src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java delete mode 100644 src/main/java/biz/nynja/search/services/AccountServiceImpl.java create mode 100644 src/main/java/biz/nynja/search/services/SearchServiceImpl.java delete mode 100644 src/main/resources/application-production.yml diff --git a/pom.xml b/pom.xml index 9dca968..60f25f3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - biz.nynja.search + biz.nynja.search.grpc search-service 0.0.1-SNAPSHOT jar @@ -77,15 +77,31 @@ 1.6.1 + + org.springframework.boot + spring-boot-starter-data-cassandra + + + + com.datastax.cassandra + cassandra-driver-core + + + io.netty + netty-handler + + + + com.google.guava guava 21.0 - + libs-snapshot-local.biz.nynja.protos - search-intracoldev + search-service-intracoldev 1.0-SNAPSHOT @@ -95,6 +111,12 @@ + + com.googlecode.libphonenumber + libphonenumber + 8.9.12 + + com.fasterxml.jackson.core jackson-databind @@ -112,6 +134,15 @@ groovy-all + + io.micrometer + micrometer-core + + + + io.micrometer + micrometer-registry-prometheus + diff --git a/src/main/java/biz/nynja/search/healthindicators/GrpcServerHealthIndicator.java b/src/main/java/biz/nynja/search/healthindicators/GrpcServerHealthIndicator.java index cb98dd5..3e0c604 100644 --- a/src/main/java/biz/nynja/search/healthindicators/GrpcServerHealthIndicator.java +++ b/src/main/java/biz/nynja/search/healthindicators/GrpcServerHealthIndicator.java @@ -13,8 +13,8 @@ import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; -import biz.nynja.search.grpc.AccountServiceGrpc; -import biz.nynja.search.services.AccountServiceImpl; +import biz.nynja.search.grpc.SearchServiceGrpc; +import biz.nynja.search.services.SearchServiceImpl; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.health.v1.HealthCheckRequest; @@ -27,7 +27,7 @@ import io.grpc.health.v1.HealthGrpc; @Component public class GrpcServerHealthIndicator implements HealthIndicator { - private static final Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SearchServiceImpl.class); @Autowired protected GRpcServerProperties gRpcServerProperties; @@ -37,14 +37,14 @@ public class GrpcServerHealthIndicator implements HealthIndicator { ManagedChannel channel = onChannelBuild( ManagedChannelBuilder.forAddress("localhost", gRpcServerProperties.getPort()).usePlaintext()).build(); final HealthCheckRequest healthCheckRequest = HealthCheckRequest.newBuilder() - .setService(AccountServiceGrpc.getServiceDescriptor().getName()).build(); + .setService(SearchServiceGrpc.getServiceDescriptor().getName()).build(); final HealthGrpc.HealthFutureStub healthFutureStub = HealthGrpc.newFutureStub(channel); HealthCheckResponse.ServingStatus servingStatus = null; try { servingStatus = healthFutureStub.check(healthCheckRequest).get().getStatus(); } catch (InterruptedException | ExecutionException e) { LOGGER.error("Error retrieving health status for {}: {}", - AccountServiceGrpc.getServiceDescriptor().getName(), e.getMessage()); + SearchServiceGrpc.getServiceDescriptor().getName(), e.getMessage()); LOGGER.debug(null, e.getCause()); return Health.down().build(); } diff --git a/src/main/java/biz/nynja/search/models/AccountInfo.java b/src/main/java/biz/nynja/search/models/AccountInfo.java deleted file mode 100644 index 817cba1..0000000 --- a/src/main/java/biz/nynja/search/models/AccountInfo.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (C) 2018 Nynja Inc. All rights reserved. - */ -package biz.nynja.search.models; - -import org.springframework.data.cassandra.core.mapping.PrimaryKey; -import org.springframework.data.cassandra.core.mapping.Table; - -import biz.nynja.search.grpc.RegisterRequest; - -/** - * Account bean as represented in the corresponding Cassandra table. - */ -@Table -public class AccountInfo { - - @PrimaryKey - private Long id; - private String email; - private String password; - - public AccountInfo() { - } - - public AccountInfo(long id, String email, String password) { - this.id = id; - this.email = email; - this.password = password; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public String toString() { - return "AccountInfo [id=" + id + ", email=" + email + ", password=" + password + "]"; - } - - public static AccountInfo fromProto(RegisterRequest proto) { - AccountInfo accountInfo = new AccountInfo(); - accountInfo.setId(proto.getId()); - accountInfo.setEmail(proto.getEmail()); - accountInfo.setPassword(proto.getPassword()); - return accountInfo; - } - - public biz.nynja.blueprint.grpc.AccountInfo toProto() { - return biz.nynja.blueprint.grpc.AccountInfo.newBuilder().setId(Long.toString(getId())).setEmail(getEmail()) - .build(); - } -} diff --git a/src/main/java/biz/nynja/search/repositories/AccountInfoRepository.java b/src/main/java/biz/nynja/search/repositories/AccountInfoRepository.java deleted file mode 100644 index bce17d8..0000000 --- a/src/main/java/biz/nynja/search/repositories/AccountInfoRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (C) 2018 Nynja Inc. All rights reserved. - */ -package biz.nynja.search.repositories; - -import org.springframework.data.cassandra.repository.Query; -import org.springframework.data.repository.CrudRepository; - -import biz.nynja.search.models.AccountInfo; - -/** - * Account repository for Cassandra operations/queries. - */ -public interface AccountInfoRepository extends CrudRepository { - - @Query(value = "SELECT * FROM AccountInfo WHERE email=?0 ALLOW FILTERING") - public AccountInfo findByEmail(String email); -} diff --git a/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java b/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java new file mode 100644 index 0000000..d0782b6 --- /dev/null +++ b/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.search.services; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import biz.nynja.search.grpc.SearchServiceGrpc; +import biz.nynja.search.grpc.SearchByEmailRequest; +import biz.nynja.search.grpc.SearchByPhoneNumberRequest; +import biz.nynja.search.grpc.SearchByQrCodeRequest; +import biz.nynja.search.grpc.SearchByUsernameRequest; +import biz.nynja.search.grpc.SearchResponse; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +@Service +public class AccountServiceCommunicator { + + @Value("${services.account.address}") + private String accountServiceAddress; + + @Value("${services.account.port}") + private Integer accountServicePort; + + public SearchResponse searchByUsername(String username) { + SearchByUsernameRequest request = SearchByUsernameRequest.newBuilder().setUsername(username).build(); + + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + .usePlaintext().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(managedChannel); + + SearchResponse response = searchServiceBlockingStub.searchByUsername(request); + return response; + } + + public SearchResponse searchByPhoneNumber(String phoneNumber) { + SearchByPhoneNumberRequest request = SearchByPhoneNumberRequest.newBuilder().setPhoneNumber(phoneNumber) + .build(); + + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + .usePlaintext().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(managedChannel); + + SearchResponse response = searchServiceBlockingStub.searchByPhoneNumber(request); + return response; + } + + public SearchResponse searchByEmail(String email) { + SearchByEmailRequest request = SearchByEmailRequest.newBuilder().setEmail(email).build(); + + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + .usePlaintext().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(managedChannel); + + SearchResponse response = searchServiceBlockingStub.searchByEmail(request); + return response; + } + + public SearchResponse searchByQrCode(String qrcode) { + SearchByQrCodeRequest request = SearchByQrCodeRequest.newBuilder().setQrCode(qrcode).build(); + + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + .usePlaintext().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(managedChannel); + + SearchResponse response = searchServiceBlockingStub.searchByQrCode(request); + return response; + } + +} diff --git a/src/main/java/biz/nynja/search/services/AccountServiceImpl.java b/src/main/java/biz/nynja/search/services/AccountServiceImpl.java deleted file mode 100644 index 665ee36..0000000 --- a/src/main/java/biz/nynja/search/services/AccountServiceImpl.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (C) 2018 Nynja Inc. All rights reserved. - */ -package biz.nynja.search.services; - -import org.lognet.springboot.grpc.GRpcService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import biz.nynja.search.grpc.AccountServiceGrpc; -import biz.nynja.search.grpc.RegisterError; -import biz.nynja.search.grpc.RegisterRequest; -import biz.nynja.search.grpc.RegisterResponse; -import biz.nynja.search.grpc.RegisterError.Cause; -import biz.nynja.search.models.AccountInfo; -import biz.nynja.search.repositories.AccountInfoRepository; -import io.grpc.stub.StreamObserver; - -/** - * gRPC Account service implementation.
- * The service extends the protobuf generated class and overrides the needed methods. It also saves/retrieves the - * account information via {@link AccountInfoRepository}. - */ -@GRpcService -public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBase { - - private static final Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class); - - @Autowired - private AccountInfoRepository accountInfoRepository; - - @Override - public void register(RegisterRequest request, StreamObserver responseObserver) { - - logger.info("Got a gRPC service request: {}", request); - - AccountInfo accountInfo = AccountInfo.fromProto(request); - - if (accountInfoRepository.findByEmail(accountInfo.getEmail()) != null) { - responseObserver.onNext(RegisterResponse.newBuilder() - .setError(RegisterError.newBuilder().setCause(Cause.EMAIL_ALREADY_USED)).build()); - responseObserver.onCompleted(); - return; - } - - AccountInfo savedAccount = accountInfoRepository.save(accountInfo); - logger.info("Account \"{}\" saved into the DB", savedAccount.toString()); - - RegisterResponse response = RegisterResponse.newBuilder().setAccount(savedAccount.toProto()).build(); - logger.info("Response from gRPC service: \"{}\"", response); - - responseObserver.onNext(response); - responseObserver.onCompleted(); - } -} diff --git a/src/main/java/biz/nynja/search/services/SearchServiceImpl.java b/src/main/java/biz/nynja/search/services/SearchServiceImpl.java new file mode 100644 index 0000000..b169440 --- /dev/null +++ b/src/main/java/biz/nynja/search/services/SearchServiceImpl.java @@ -0,0 +1,143 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.search.services; + +import org.lognet.springboot.grpc.GRpcService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import biz.nynja.search.grpc.SearchServiceGrpc; +import biz.nynja.search.grpc.ErrorResponse; +import biz.nynja.search.grpc.ErrorResponse.Cause; +import biz.nynja.search.grpc.SearchByEmailRequest; +import biz.nynja.search.grpc.SearchByPhoneNumberRequest; +import biz.nynja.search.grpc.SearchByQrCodeRequest; +import biz.nynja.search.grpc.SearchByUsernameRequest; +import biz.nynja.search.grpc.SearchResponse; +import io.grpc.stub.StreamObserver; + +/** + * gRPC Account service implementation.
+ * The service extends the protobuf generated class and overrides the needed methods. It also saves/retrieves the + * account information via {@link AccountInfoRepository}. + */ +@GRpcService +public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { + + private static final Logger logger = LoggerFactory.getLogger(SearchServiceImpl.class); + + @Autowired + private AccountServiceCommunicator accountService; + + @Override + public void searchByUsername(SearchByUsernameRequest request, StreamObserver responseObserver) { + + logger.info("Searching account by username {}", request.getUsername()); + if (request.getUsername().isEmpty()) { + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_USERNAME)).build()); + responseObserver.onCompleted(); + return; + } + + SearchResponse response = accountService.searchByUsername(request.getUsername()); + + if (response.getError().getCauseValue() != 0) { + logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); + responseObserver.onCompleted(); + return; + } + + logger.debug("Found result for search by username {}: \"{}\"", request.getUsername(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + return; + } + + @Override + public void searchByPhoneNumber(SearchByPhoneNumberRequest request, + StreamObserver responseObserver) { + + logger.info("Searching account by phone number {}", request.getPhoneNumber()); + if (request.getPhoneNumber().isEmpty()) { + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PHONENUMBER)).build()); + responseObserver.onCompleted(); + return; + } + + SearchResponse response = accountService.searchByPhoneNumber(request.getPhoneNumber()); + + if (response.getError().getCauseValue() != 0) { + logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); + responseObserver.onCompleted(); + return; + } + + logger.debug("Found result for search by phone number {}: \"{}\"", request.getPhoneNumber(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + return; + } + + @Override + public void searchByEmail(SearchByEmailRequest request, StreamObserver responseObserver) { + + logger.info("Searching account by e-mail {}", request.getEmail()); + if (request.getEmail().isEmpty()) { + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_EMAIL)).build()); + responseObserver.onCompleted(); + return; + } + + SearchResponse response = accountService.searchByEmail(request.getEmail()); + + if (response.getError().getCauseValue() != 0) { + logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); + responseObserver.onCompleted(); + return; + } + + logger.debug("Found result for search by phone number {}: \"{}\"", request.getEmail(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + return; + } + + @Override + public void searchByQrCode(SearchByQrCodeRequest request, StreamObserver responseObserver) { + + logger.info("Searching account by QR code {}", request.getQrCode()); + if (request.getQrCode().isEmpty()) { + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_QR_CODE)).build()); + responseObserver.onCompleted(); + return; + } + + SearchResponse response = accountService.searchByQrCode(request.getQrCode()); + + if (response.getError().getCauseValue() != 0) { + logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); + responseObserver.onCompleted(); + return; + } + + logger.debug("Found result for search by phone number {}: \"{}\"", request.getQrCode(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + return; + } + +} \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index d33d261..c957c8e 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,7 +1,13 @@ grpc: enabled: true enableReflection: false - port: 6568 - + port: 6567 + +services: + account: + address: 127.0.0.1 + port: 6565 + server: - port: 8084 \ No newline at end of file + port: 8018 + diff --git a/src/main/resources/application-production.yml b/src/main/resources/application-production.yml deleted file mode 100644 index 6280131..0000000 --- a/src/main/resources/application-production.yml +++ /dev/null @@ -1,7 +0,0 @@ -grpc: - enabled: ${GRPC_ENABLED:true} - enableReflection: ${GRPC_ENABLE_REFLECTION:false} - port: ${GRPC_SERVER_PORT:6568} - -server: - port: ${APPLICATION_SERVER_PORT:8084} \ No newline at end of file diff --git a/src/main/resources/logback-spring.groovy b/src/main/resources/logback-spring.groovy index 82f9fa7..5c01a5b 100644 --- a/src/main/resources/logback-spring.groovy +++ b/src/main/resources/logback-spring.groovy @@ -3,6 +3,7 @@ */ import ch.qos.logback.classic.encoder.PatternLayoutEncoder +import ch.qos.logback.core.ConsoleAppender import ch.qos.logback.core.rolling.RollingFileAppender import ch.qos.logback.core.rolling.TimeBasedRollingPolicy import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP @@ -11,7 +12,7 @@ import ch.qos.logback.classic.Level statusListener(OnConsoleStatusListener) -def file = "${System.getProperty('log.dir', '')}blueprint-java-spring-service-%d.%i.log" +def file = "${System.getProperty('log.dir', '')}search-service-%d.%i.log" appender("FILE", RollingFileAppender) { // add a status message regarding the file property @@ -23,6 +24,10 @@ appender("FILE", RollingFileAppender) { timeBasedFileNamingAndTriggeringPolicy(SizeAndTimeBasedFNATP) { maxFileSize = "10mb" }} } -logger("org.springframework.cloud.config.client.ConfigServicePropertySourceLocator", Level.WARN) +appender("Console-Appender", ConsoleAppender) { + encoder(PatternLayoutEncoder) { pattern = "%d{HH:mm:ss.SSS} %level %logger - %msg%n" } +} +logger("org.springframework.cloud.config.client.ConfigServicePropertySourceLocator", Level.WARN) +root(INFO, ["Console-Appender"]) root(Level.toLevel("${System.getProperty('log.level', 'INFO')}"), ["FILE"]) \ No newline at end of file diff --git a/src/test/java/biz/nynja/search/ApplicationTests.java b/src/test/java/biz/nynja/search/ApplicationTests.java index 9ae2bf5..87547cb 100644 --- a/src/test/java/biz/nynja/search/ApplicationTests.java +++ b/src/test/java/biz/nynja/search/ApplicationTests.java @@ -11,8 +11,8 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; -import biz.nynja.search.models.AccountInfo; -import biz.nynja.search.repositories.AccountInfoRepository; +//import biz.nynja.search.models.AccountInfo; +//import biz.nynja.search.repositories.AccountInfoRepository; @RunWith(SpringRunner.class) @SpringBootTest(classes = Util.class, @@ -22,16 +22,19 @@ import biz.nynja.search.repositories.AccountInfoRepository; @ActiveProfiles("dev") public class ApplicationTests extends GrpcServerTestBase { - @MockBean - private AccountInfoRepository accountInfoRepository; - - @Autowired - @Qualifier("newAccount") - private AccountInfo accountInfo; - - @Autowired - @Qualifier("savedAccount") - private AccountInfo savedAccount; +// @MockBean +// private AccountInfoRepository accountInfoRepository; +// +// @Autowired +// @Qualifier("newAccount") +// private AccountInfo accountInfo; +// +// @Autowired +// @Qualifier("savedAccount") +// private AccountInfo savedAccount; + +//************************************************************************************************************* + // // @Test // public void testRegister() throws ExecutionException, InterruptedException { diff --git a/src/test/java/biz/nynja/search/Util.java b/src/test/java/biz/nynja/search/Util.java index 8bf2aae..8fa4d7a 100644 --- a/src/test/java/biz/nynja/search/Util.java +++ b/src/test/java/biz/nynja/search/Util.java @@ -3,7 +3,7 @@ package biz.nynja.search; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; -import biz.nynja.search.models.AccountInfo;; +//import biz.nynja.search.models.AccountInfo;; @TestConfiguration public class Util { @@ -12,21 +12,21 @@ public class Util { public static final String EMAIL = "email@test.com"; public static final String PASSWORD = "abc"; - @Bean - public AccountInfo newAccount() { - AccountInfo accountInfo = new AccountInfo(); - accountInfo.setId(ID); - accountInfo.setEmail(EMAIL); - accountInfo.setPassword(PASSWORD); - return accountInfo; - } - - @Bean - public AccountInfo savedAccount() { - AccountInfo accountInfo = new AccountInfo(); - accountInfo.setId(ID); - accountInfo.setEmail(EMAIL); - accountInfo.setPassword(PASSWORD); - return accountInfo; - } +// @Bean +// public AccountInfo newAccount() { +// AccountInfo accountInfo = new AccountInfo(); +// accountInfo.setId(ID); +// accountInfo.setEmail(EMAIL); +// accountInfo.setPassword(PASSWORD); +// return accountInfo; +// } +// +// @Bean +// public AccountInfo savedAccount() { +// AccountInfo accountInfo = new AccountInfo(); +// accountInfo.setId(ID); +// accountInfo.setEmail(EMAIL); +// accountInfo.setPassword(PASSWORD); +// return accountInfo; +// } } -- GitLab From bff32b2ae0009f7936bc236cd629cfcc0435dc83 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Fri, 19 Oct 2018 10:23:15 +0300 Subject: [PATCH 2/4] NY_3810: Code review corrections Signed-off-by: Stoyan Tzenkov --- .../search/services/SearchServiceImpl.java | 53 +++++++------------ src/main/resources/application-dev.yml | 4 ++ 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/main/java/biz/nynja/search/services/SearchServiceImpl.java b/src/main/java/biz/nynja/search/services/SearchServiceImpl.java index b169440..29bcbc8 100644 --- a/src/main/java/biz/nynja/search/services/SearchServiceImpl.java +++ b/src/main/java/biz/nynja/search/services/SearchServiceImpl.java @@ -35,20 +35,15 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { public void searchByUsername(SearchByUsernameRequest request, StreamObserver responseObserver) { logger.info("Searching account by username {}", request.getUsername()); - if (request.getUsername().isEmpty()) { - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_USERNAME)).build()); - responseObserver.onCompleted(); + if ((request.getUsername() == null) || request.getUsername().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, "Missing username: {}", Cause.MISSING_USERNAME); return; } SearchResponse response = accountService.searchByUsername(request.getUsername()); - if (response.getError().getCauseValue() != 0) { - logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); - responseObserver.onCompleted(); + if ((response.getError() != null) && (response.getError().getCauseValue() != 0)) { + logAndBuildGrpcResponse(responseObserver, "Account service returns an error with the cause: {}", response.getError().getCause()); return; } @@ -63,20 +58,15 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { StreamObserver responseObserver) { logger.info("Searching account by phone number {}", request.getPhoneNumber()); - if (request.getPhoneNumber().isEmpty()) { - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PHONENUMBER)).build()); - responseObserver.onCompleted(); + if ((request.getPhoneNumber() == null) || request.getPhoneNumber().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, "Missing phone number: {}", Cause.MISSING_PHONENUMBER); return; } SearchResponse response = accountService.searchByPhoneNumber(request.getPhoneNumber()); if (response.getError().getCauseValue() != 0) { - logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); - responseObserver.onCompleted(); + logAndBuildGrpcResponse(responseObserver, "Account service returns an error with the cause: {}", response.getError().getCause()); return; } @@ -90,20 +80,15 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { public void searchByEmail(SearchByEmailRequest request, StreamObserver responseObserver) { logger.info("Searching account by e-mail {}", request.getEmail()); - if (request.getEmail().isEmpty()) { - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_EMAIL)).build()); - responseObserver.onCompleted(); + if ((request.getEmail() == null) || request.getEmail().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, "Missing e-mail: {}", Cause.MISSING_EMAIL); return; } SearchResponse response = accountService.searchByEmail(request.getEmail()); if (response.getError().getCauseValue() != 0) { - logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); - responseObserver.onCompleted(); + logAndBuildGrpcResponse(responseObserver, "Account service returns an error with the cause: {}", response.getError().getCause()); return; } @@ -117,20 +102,15 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { public void searchByQrCode(SearchByQrCodeRequest request, StreamObserver responseObserver) { logger.info("Searching account by QR code {}", request.getQrCode()); - if (request.getQrCode().isEmpty()) { - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_QR_CODE)).build()); - responseObserver.onCompleted(); + if ((request.getQrCode() == null) || request.getQrCode().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, "Missing QR code: {}", Cause.MISSING_QR_CODE); return; } SearchResponse response = accountService.searchByQrCode(request.getQrCode()); if (response.getError().getCauseValue() != 0) { - logger.debug("Account service returns an error with the cause {}", response.getError().getCause()); - responseObserver.onNext(SearchResponse.newBuilder() - .setError(ErrorResponse.newBuilder().setCause(response.getError().getCause())).build()); - responseObserver.onCompleted(); + logAndBuildGrpcResponse(responseObserver, "Account service returns an error with the cause: {}", response.getError().getCause()); return; } @@ -140,4 +120,11 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { return; } + private static void logAndBuildGrpcResponse(StreamObserver responseObserver, String logMessage, Cause cause) { + logger.debug(logMessage, cause.toString()); + responseObserver.onNext(SearchResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(cause)).build()); + responseObserver.onCompleted(); + } + } \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index c957c8e..b8525f8 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -2,6 +2,10 @@ grpc: enabled: true enableReflection: false port: 6567 + unitTest: + port: + searchServiceTest: 10002 + services: account: -- GitLab From 9949b7a59453d3c48f747667cded347835f7eb37 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Mon, 22 Oct 2018 11:48:42 +0300 Subject: [PATCH 3/4] NY_3607: Code review recommendations implemented. Signed-off-by: Stoyan Tzenkov --- .../configuration/SearchAccountConfig.java | 38 +++++++++++++++++++ .../services/AccountServiceCommunicator.java | 17 ++++----- .../search/services/SearchServiceImpl.java | 6 +-- 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java diff --git a/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java b/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java new file mode 100644 index 0000000..90ff3a4 --- /dev/null +++ b/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java @@ -0,0 +1,38 @@ +package biz.nynja.search.configuration; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class SearchAccountConfig { + + private final String accountServiceAddress; + private final int accountServicePort; + + @Autowired + public SearchAccountConfig(Environment env) { + this.accountServiceAddress = env.getRequiredProperty("services.account.address"); + this.accountServicePort = parseProperty(env, "services.account.port"); + } + + private int parseProperty(Environment env, String property) throws InternalError { + int intProperty = 0; + try { + intProperty = Integer.parseInt(env.getRequiredProperty(property)); + } catch (NumberFormatException ex) { + throw new InternalError("Integer expected in " + property); + } + return intProperty; + + } + + public String getAccountServiceAddress() { + return accountServiceAddress; + } + + public int getAccountServicePort() { + return accountServicePort; + } + +} diff --git a/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java b/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java index d0782b6..4118557 100644 --- a/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java +++ b/src/main/java/biz/nynja/search/services/AccountServiceCommunicator.java @@ -3,10 +3,12 @@ */ package biz.nynja.search.services; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import biz.nynja.search.grpc.SearchServiceGrpc; +import biz.nynja.search.configuration.SearchAccountConfig; import biz.nynja.search.grpc.SearchByEmailRequest; import biz.nynja.search.grpc.SearchByPhoneNumberRequest; import biz.nynja.search.grpc.SearchByQrCodeRequest; @@ -18,16 +20,13 @@ import io.grpc.ManagedChannelBuilder; @Service public class AccountServiceCommunicator { - @Value("${services.account.address}") - private String accountServiceAddress; - - @Value("${services.account.port}") - private Integer accountServicePort; + @Autowired + private SearchAccountConfig searchAccountConfig; public SearchResponse searchByUsername(String username) { SearchByUsernameRequest request = SearchByUsernameRequest.newBuilder().setUsername(username).build(); - ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(searchAccountConfig.getAccountServiceAddress(), searchAccountConfig.getAccountServicePort()) .usePlaintext().build(); final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc @@ -41,7 +40,7 @@ public class AccountServiceCommunicator { SearchByPhoneNumberRequest request = SearchByPhoneNumberRequest.newBuilder().setPhoneNumber(phoneNumber) .build(); - ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(searchAccountConfig.getAccountServiceAddress(), searchAccountConfig.getAccountServicePort()) .usePlaintext().build(); final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc @@ -54,7 +53,7 @@ public class AccountServiceCommunicator { public SearchResponse searchByEmail(String email) { SearchByEmailRequest request = SearchByEmailRequest.newBuilder().setEmail(email).build(); - ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(searchAccountConfig.getAccountServiceAddress(), searchAccountConfig.getAccountServicePort()) .usePlaintext().build(); final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc @@ -67,7 +66,7 @@ public class AccountServiceCommunicator { public SearchResponse searchByQrCode(String qrcode) { SearchByQrCodeRequest request = SearchByQrCodeRequest.newBuilder().setQrCode(qrcode).build(); - ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(accountServiceAddress, accountServicePort) + ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(searchAccountConfig.getAccountServiceAddress(), searchAccountConfig.getAccountServicePort()) .usePlaintext().build(); final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc diff --git a/src/main/java/biz/nynja/search/services/SearchServiceImpl.java b/src/main/java/biz/nynja/search/services/SearchServiceImpl.java index 29bcbc8..d0c67cf 100644 --- a/src/main/java/biz/nynja/search/services/SearchServiceImpl.java +++ b/src/main/java/biz/nynja/search/services/SearchServiceImpl.java @@ -19,9 +19,9 @@ import biz.nynja.search.grpc.SearchResponse; import io.grpc.stub.StreamObserver; /** - * gRPC Account service implementation.
- * The service extends the protobuf generated class and overrides the needed methods. It also saves/retrieves the - * account information via {@link AccountInfoRepository}. + * gRPC Search service implementation.
+ * The service extends the protobuf generated class and overrides the needed methods. + * It also saves/retrieves the account information via the Account service. */ @GRpcService public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { -- GitLab From ee69ad2cb3d33ca8eccf4de5f6cb98ba03298821 Mon Sep 17 00:00:00 2001 From: Stoyan Tzenkov Date: Tue, 23 Oct 2018 10:20:28 +0300 Subject: [PATCH 4/4] NY_3706: Unit tests added Signed-off-by: Stoyan Tzenkov --- .../configuration/SearchAccountConfig.java | 9 +- .../biz/nynja/search/ApplicationTests.java | 344 +++++++++++++++--- src/test/java/biz/nynja/search/Util.java | 58 +-- 3 files changed, 328 insertions(+), 83 deletions(-) diff --git a/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java b/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java index 90ff3a4..c999177 100644 --- a/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java +++ b/src/main/java/biz/nynja/search/configuration/SearchAccountConfig.java @@ -10,21 +10,18 @@ public class SearchAccountConfig { private final String accountServiceAddress; private final int accountServicePort; - @Autowired +// @Autowired public SearchAccountConfig(Environment env) { this.accountServiceAddress = env.getRequiredProperty("services.account.address"); - this.accountServicePort = parseProperty(env, "services.account.port"); + this.accountServicePort = parseProperty(env, "services.account.port"); } private int parseProperty(Environment env, String property) throws InternalError { - int intProperty = 0; try { - intProperty = Integer.parseInt(env.getRequiredProperty(property)); + return Integer.parseInt(env.getRequiredProperty(property)); } catch (NumberFormatException ex) { throw new InternalError("Integer expected in " + property); } - return intProperty; - } public String getAccountServiceAddress() { diff --git a/src/test/java/biz/nynja/search/ApplicationTests.java b/src/test/java/biz/nynja/search/ApplicationTests.java index 87547cb..8ad6367 100644 --- a/src/test/java/biz/nynja/search/ApplicationTests.java +++ b/src/test/java/biz/nynja/search/ApplicationTests.java @@ -3,6 +3,14 @@ */ package biz.nynja.search; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.BDDMockito.given; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -11,68 +19,294 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; -//import biz.nynja.search.models.AccountInfo; -//import biz.nynja.search.repositories.AccountInfoRepository; +import biz.nynja.search.grpc.ErrorResponse.Cause; +import biz.nynja.search.grpc.ErrorResponse; +import biz.nynja.search.grpc.SearchByEmailRequest; +import biz.nynja.search.grpc.SearchByPhoneNumberRequest; +import biz.nynja.search.grpc.SearchByQrCodeRequest; +import biz.nynja.search.grpc.SearchByUsernameRequest; +import biz.nynja.search.grpc.SearchResponse; +import biz.nynja.search.grpc.SearchServiceGrpc; +import biz.nynja.search.services.AccountServiceCommunicator; @RunWith(SpringRunner.class) @SpringBootTest(classes = Util.class, - properties = { + properties = { "grpc.port=${grpc.unitTest.port.searchServiceTest}", "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration", "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration" }) @ActiveProfiles("dev") public class ApplicationTests extends GrpcServerTestBase { -// @MockBean -// private AccountInfoRepository accountInfoRepository; -// -// @Autowired -// @Qualifier("newAccount") -// private AccountInfo accountInfo; -// -// @Autowired -// @Qualifier("savedAccount") -// private AccountInfo savedAccount; - -//************************************************************************************************************* - - // - // @Test - // public void testRegister() throws ExecutionException, InterruptedException { - // - // String testEmail = "email@test.com"; - // final RegisterRequest request = RegisterRequest.newBuilder().setId(1).setEmail(testEmail).setPassword("abc") - // .build(); - // - // given(accountInfoRepository.findByEmail(testEmail)).willReturn(null); - // given(accountInfoRepository.save(any(AccountInfo.class))).willReturn(savedAccount); - // - // final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - // .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); - // - // final RegisterResponse reply = accountServiceBlockingStub.register(request); - // - // assertNotNull("Reply should not be null", reply); - // assertTrue(String.format("Reply should contain email '%s'", testEmail), - // reply.getAccount().getEmail().equals(testEmail)); - // } - // - // @Test - // public void testRegisterExistEmail() throws ExecutionException, InterruptedException { - // - // String testEmail = "email@test.com"; - // final RegisterRequest request = RegisterRequest.newBuilder().setId(1).setEmail(testEmail).setPassword("abc") - // .build(); - // - // given(accountInfoRepository.findByEmail(testEmail)).willReturn(accountInfo); - // - // final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc - // .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); - // - // final RegisterResponse reply = accountServiceBlockingStub.register(request); - // - // assertNotNull("Reply should not be null", reply); - // assertTrue(String.format("Reply should contain cause '%s'", testEmail), - // reply.getError().getCause().equals(RegisterError.Cause.EMAIL_ALREADY_USED)); - // } + @MockBean + private AccountServiceCommunicator accountService; + + @Autowired + @Qualifier("savedResponse") + private SearchResponse savedResponse; + + @Test + public void testSearchByUsername() throws ExecutionException, InterruptedException { + final SearchByUsernameRequest request = SearchByUsernameRequest.newBuilder() + .setUsername(Util.USERNAME).build(); + + SearchResponse response = savedResponse; + + given(accountService.searchByUsername(request.getUsername())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", Util.LAST_NAME.toString()), + reply.getSearchResultDetails().getLastName().equals(Util.LAST_NAME.toString())); + } + + @Test + public void testSearchByUsernameNotFound() throws ExecutionException, InterruptedException { + final SearchByUsernameRequest request = SearchByUsernameRequest.newBuilder() + .setUsername(Util.USERNAME).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.USERNAME_NOT_FOUND))).build(); + + given(accountService.searchByUsername(request.getUsername())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", biz.nynja.search.grpc.ErrorResponse.Cause.USERNAME_NOT_FOUND), + reply.getError().getCause().equals(biz.nynja.search.grpc.ErrorResponse.Cause.USERNAME_NOT_FOUND)); + } + + @Test + public void testSearchByUsernameBadRequest() throws ExecutionException, InterruptedException { + final SearchByUsernameRequest request = SearchByUsernameRequest.newBuilder().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_USERNAME), + reply.getError().getCause().equals(Cause.MISSING_USERNAME)); + } + + @Test + public void testSearchByUsernameInvalid() { + final SearchByUsernameRequest request = SearchByUsernameRequest.newBuilder() + .setUsername(Util.INVALID_USERNAME).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.INVALID_USERNAME))).build(); + + given(accountService.searchByUsername(request.getUsername())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.INVALID_USERNAME), + reply.getError().getCause().equals(Cause.INVALID_USERNAME)); + } + + @Test + public void testSearchByPhoneNumber() throws ExecutionException, InterruptedException { + final SearchByPhoneNumberRequest request = SearchByPhoneNumberRequest.newBuilder() + .setPhoneNumber(Util.PHONE_NUMBER).build(); + + SearchResponse response = savedResponse; + + given(accountService.searchByPhoneNumber(request.getPhoneNumber())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", Util.LAST_NAME.toString()), + reply.getSearchResultDetails().getLastName().equals(Util.LAST_NAME.toString())); + } + + @Test + public void testSearchByPhoneNumberNotFound() throws ExecutionException, InterruptedException { + final SearchByPhoneNumberRequest request = SearchByPhoneNumberRequest.newBuilder() + .setPhoneNumber(Util.PHONE_NUMBER).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.PHONENUMBER_NOT_FOUND))).build(); + + given(accountService.searchByPhoneNumber(request.getPhoneNumber())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", biz.nynja.search.grpc.ErrorResponse.Cause.PHONENUMBER_NOT_FOUND), + reply.getError().getCause().equals(biz.nynja.search.grpc.ErrorResponse.Cause.PHONENUMBER_NOT_FOUND)); + } + + @Test + public void testSearchByPhoneNumberBadRequest() throws ExecutionException, InterruptedException { + final SearchByPhoneNumberRequest request = SearchByPhoneNumberRequest.newBuilder().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_PHONENUMBER), + reply.getError().getCause().equals(Cause.MISSING_PHONENUMBER)); + } + + @Test + public void testSearchByPhoneNumberInvalid() { + final SearchByPhoneNumberRequest request = SearchByPhoneNumberRequest.newBuilder() + .setPhoneNumber(Util.INVALID_PHONENUMBER).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.INVALID_PHONENUMBER))).build(); + + given(accountService.searchByPhoneNumber(request.getPhoneNumber())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.INVALID_PHONENUMBER), + reply.getError().getCause().equals(Cause.INVALID_PHONENUMBER)); + } + + @Test + public void testSearchByEmail() throws ExecutionException, InterruptedException { + final SearchByEmailRequest request = SearchByEmailRequest.newBuilder() + .setEmail(Util.EMAIL).build(); + + SearchResponse response = savedResponse; + + given(accountService.searchByEmail(request.getEmail())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", Util.LAST_NAME.toString()), + reply.getSearchResultDetails().getLastName().equals(Util.LAST_NAME.toString())); + } + + @Test + public void testSearchByEmailNotFound() throws ExecutionException, InterruptedException { + final SearchByEmailRequest request = SearchByEmailRequest.newBuilder() + .setEmail(Util.EMAIL).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.EMAIL_NOT_FOUND))).build(); + + given(accountService.searchByEmail(request.getEmail())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", biz.nynja.search.grpc.ErrorResponse.Cause.EMAIL_NOT_FOUND), + reply.getError().getCause().equals(biz.nynja.search.grpc.ErrorResponse.Cause.EMAIL_NOT_FOUND)); + } + + @Test + public void testSearchByEmailBadRequest() throws ExecutionException, InterruptedException { + final SearchByEmailRequest request = SearchByEmailRequest.newBuilder().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_EMAIL), + reply.getError().getCause().equals(Cause.MISSING_EMAIL)); + } + + @Test + public void testSearchByEmailInvalid() { + final SearchByEmailRequest request = SearchByEmailRequest.newBuilder() + .setEmail(Util.INVALID_EMAIL).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.INVALID_EMAIL))).build(); + + given(accountService.searchByEmail(request.getEmail())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.INVALID_EMAIL), + reply.getError().getCause().equals(Cause.INVALID_EMAIL)); + } + + @Test + public void testSearchByQrCode() throws ExecutionException, InterruptedException { + final SearchByQrCodeRequest request = SearchByQrCodeRequest.newBuilder() + .setQrCode(Util.QR_CODE).build(); + + SearchResponse response = savedResponse; + + given(accountService.searchByQrCode(request.getQrCode())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByQrCode(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", Util.LAST_NAME.toString()), + reply.getSearchResultDetails().getLastName().equals(Util.LAST_NAME.toString())); + } + + @Test + public void testSearchByQrCodeNotFound() throws ExecutionException, InterruptedException { + final SearchByQrCodeRequest request = SearchByQrCodeRequest.newBuilder() + .setQrCode(Util.QR_CODE).build(); + + SearchResponse response = SearchResponse.newBuilder().setError((ErrorResponse.newBuilder().setCause(Cause.QR_CODE_NOT_FOUND))).build(); + + given(accountService.searchByQrCode(request.getQrCode())).willReturn(response); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByQrCode(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", biz.nynja.search.grpc.ErrorResponse.Cause.QR_CODE_NOT_FOUND), + reply.getError().getCause().equals(biz.nynja.search.grpc.ErrorResponse.Cause.QR_CODE_NOT_FOUND)); + } + + @Test + public void testSearchByQrCodeBadRequest() throws ExecutionException, InterruptedException { + final SearchByQrCodeRequest request = SearchByQrCodeRequest.newBuilder().build(); + + final SearchServiceGrpc.SearchServiceBlockingStub searchServiceBlockingStub = SearchServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByQrCode(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_QR_CODE), + reply.getError().getCause().equals(Cause.MISSING_QR_CODE)); + } } diff --git a/src/test/java/biz/nynja/search/Util.java b/src/test/java/biz/nynja/search/Util.java index 8fa4d7a..9b9f255 100644 --- a/src/test/java/biz/nynja/search/Util.java +++ b/src/test/java/biz/nynja/search/Util.java @@ -1,32 +1,46 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ + package biz.nynja.search; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; -//import biz.nynja.search.models.AccountInfo;; +import com.google.protobuf.ByteString; + +import biz.nynja.search.grpc.SearchResponse; +import biz.nynja.search.grpc.SearchResultDetails; + +/** + * Unit tests variables, beans and help methods. + */ @TestConfiguration public class Util { - public static final Long ID = 1L; - public static final String EMAIL = "email@test.com"; - public static final String PASSWORD = "abc"; - -// @Bean -// public AccountInfo newAccount() { -// AccountInfo accountInfo = new AccountInfo(); -// accountInfo.setId(ID); -// accountInfo.setEmail(EMAIL); -// accountInfo.setPassword(PASSWORD); -// return accountInfo; -// } -// -// @Bean -// public AccountInfo savedAccount() { -// AccountInfo accountInfo = new AccountInfo(); -// accountInfo.setId(ID); -// accountInfo.setEmail(EMAIL); -// accountInfo.setPassword(PASSWORD); -// return accountInfo; -// } + public static final String USERNAME = "TomJohns"; + public static final String PHONE_NUMBER = "GB:448873598834"; + public static final String EMAIL = "p_petrov@abv.bg"; + public static final String QR_CODE = "QRcoded"; + public static final String INVALID_USERNAME = "Tom-Johns"; + public static final String INVALID_PHONENUMBER = "GB:44887359883"; // one DTMF less + public static final String INVALID_EMAIL = "p_petrov.@abv.bg"; + + public static final String AVATAR_STRING = "avatar-TomJohns"; + public static final String FIRST_NAME = "Tom"; + public static final String LAST_NAME = "Johns"; + + @Bean + public SearchResponse savedResponse() { + SearchResultDetails searchResultDetails = SearchResultDetails.newBuilder() + .setAvatar(ByteString.copyFrom(Util.AVATAR_STRING.getBytes())) + .setFirstName(Util.FIRST_NAME) + .setLastName(Util.LAST_NAME) + .build(); + SearchResponse response = SearchResponse.newBuilder() + .setSearchResultDetails(searchResultDetails).build(); + return response; + } + } -- GitLab