From 9cdbe7f73130a563992e56c98786f1c1bf69f059 Mon Sep 17 00:00:00 2001 From: marcoslop Date: Sun, 10 Jan 2021 17:17:36 +0100 Subject: [PATCH 1/4] Add lombok dependency --- src/mooc/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mooc/build.gradle b/src/mooc/build.gradle index 986f161..bb5603d 100644 --- a/src/mooc/build.gradle +++ b/src/mooc/build.gradle @@ -1,3 +1,9 @@ dependencies { compile project(":src:shared") + + compileOnly 'org.projectlombok:lombok:1.18.16' + annotationProcessor 'org.projectlombok:lombok:1.18.16' + + testCompileOnly 'org.projectlombok:lombok:1.18.16' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.16' } From d349de0203686d31a48e9a5e9b1dde714a4bd0d9 Mon Sep 17 00:00:00 2001 From: marcoslop Date: Sun, 10 Jan 2021 17:41:34 +0100 Subject: [PATCH 2/4] Event to receive Video published and publish text to twitterPubliher with a constructed text. --- .../create/SendTweetOnVideoPublished.java | 22 +++++++++++++ .../notification/domain/TwitterPublisher.java | 6 ++++ .../infrastructure/FakeTwitterPublisher.java | 10 ++++++ .../VideoPublisherCliController.java | 7 ++++- .../SendTweetOnVideoPublishedShould.java | 31 +++++++++++++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java create mode 100644 src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java create mode 100644 src/mooc/main/tv/codely/mooc/notification/infrastructure/FakeTwitterPublisher.java create mode 100644 src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java diff --git a/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java b/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java new file mode 100644 index 0000000..7d442b0 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java @@ -0,0 +1,22 @@ +package tv.codely.mooc.notification.application.create; + +import lombok.AllArgsConstructor; +import tv.codely.mooc.notification.domain.TwitterPublisher; +import tv.codely.mooc.video.domain.VideoPublished; +import tv.codely.shared.application.DomainEventSubscriber; + +@AllArgsConstructor +public class SendTweetOnVideoPublished implements DomainEventSubscriber { + + TwitterPublisher publisher; + + @Override + public Class subscribedTo() { + return VideoPublished.class; + } + + @Override + public void consume(VideoPublished event) { + publisher.tweet("New video published: " + event.title()); + } +} diff --git a/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java b/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java new file mode 100644 index 0000000..33778b7 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java @@ -0,0 +1,6 @@ +package tv.codely.mooc.notification.domain; + +public interface TwitterPublisher { + + void tweet (String text); +} diff --git a/src/mooc/main/tv/codely/mooc/notification/infrastructure/FakeTwitterPublisher.java b/src/mooc/main/tv/codely/mooc/notification/infrastructure/FakeTwitterPublisher.java new file mode 100644 index 0000000..6ce9662 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/infrastructure/FakeTwitterPublisher.java @@ -0,0 +1,10 @@ +package tv.codely.mooc.notification.infrastructure; + +import tv.codely.mooc.notification.domain.TwitterPublisher; + +public class FakeTwitterPublisher implements TwitterPublisher { + @Override + public void tweet(String text) { + //Do nothing here + } +} diff --git a/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java b/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java index 864eb8e..f0e4f7f 100644 --- a/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java +++ b/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java @@ -1,6 +1,9 @@ package tv.codely.mooc.video.infrastructure; import tv.codely.mooc.notification.application.create.SendPushToSubscribersOnVideoPublished; +import tv.codely.mooc.notification.application.create.SendTweetOnVideoPublished; +import tv.codely.mooc.notification.domain.TwitterPublisher; +import tv.codely.mooc.notification.infrastructure.FakeTwitterPublisher; import tv.codely.mooc.video.application.publish.VideoPublisher; import tv.codely.shared.application.DomainEventSubscriber; import tv.codely.shared.domain.EventBus; @@ -10,8 +13,10 @@ public class VideoPublisherCliController { public static void main(String[] args) { + final TwitterPublisher twitterPublisher = new FakeTwitterPublisher(); final Set subscribers = Set.of( - new SendPushToSubscribersOnVideoPublished() + new SendPushToSubscribersOnVideoPublished(), + new SendTweetOnVideoPublished(twitterPublisher) ); final EventBus eventBus = new ReactorEventBus(subscribers); final var videoPublisher = new VideoPublisher(eventBus); diff --git a/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java b/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java new file mode 100644 index 0000000..fcc75eb --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java @@ -0,0 +1,31 @@ +package tv.codely.mooc.notification.application.create; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tv.codely.mooc.notification.domain.TwitterPublisher; +import tv.codely.mooc.video.domain.VideoPublished; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class SendTweetOnVideoPublishedShould { + + SendTweetOnVideoPublished sendTweetOnVideoPublished; + + TwitterPublisher publisher; + + @BeforeEach + void setUp() { + publisher = mock(TwitterPublisher.class); + sendTweetOnVideoPublished = new SendTweetOnVideoPublished(publisher); + } + + @Test + void consume_should_send_text_to_twitter() { + VideoPublished videoPublished = new VideoPublished("title", "description"); + + sendTweetOnVideoPublished.consume(videoPublished); + + verify(publisher).tweet("New video published: " + videoPublished.title()); + } +} \ No newline at end of file From 830a5edcdf7cca6c808332d216ef306a9ef2453a Mon Sep 17 00:00:00 2001 From: marcoslop Date: Sun, 10 Jan 2021 17:54:03 +0100 Subject: [PATCH 3/4] Twitter4J implementation for TwitterPublisher --- src/mooc/build.gradle | 2 ++ .../infrastructure/Twitter4JPublisher.java | 36 +++++++++++++++++++ .../Twitter4JPublisherShould.java | 33 +++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java create mode 100644 src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java diff --git a/src/mooc/build.gradle b/src/mooc/build.gradle index bb5603d..16fe6b5 100644 --- a/src/mooc/build.gradle +++ b/src/mooc/build.gradle @@ -6,4 +6,6 @@ dependencies { testCompileOnly 'org.projectlombok:lombok:1.18.16' testAnnotationProcessor 'org.projectlombok:lombok:1.18.16' + + compile 'org.twitter4j:twitter4j-stream:4.0.6' } diff --git a/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java b/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java new file mode 100644 index 0000000..f809645 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java @@ -0,0 +1,36 @@ +package tv.codely.mooc.notification.infrastructure; + +import lombok.AllArgsConstructor; +import tv.codely.mooc.notification.domain.TwitterPublisher; +import twitter4j.Twitter; +import twitter4j.TwitterException; +import twitter4j.TwitterFactory; +import twitter4j.conf.ConfigurationBuilder; + +@AllArgsConstructor +public class Twitter4JPublisher implements TwitterPublisher { + + String consumerKey; + String consumerSecret; + String accessToken; + String accessTokenSecret; + + protected Twitter getTwitterInstance() { + ConfigurationBuilder cb = new ConfigurationBuilder(); + cb.setOAuthConsumerKey(consumerKey) + .setOAuthConsumerSecret(consumerSecret) + .setOAuthAccessToken(accessToken) + .setOAuthAccessTokenSecret(accessTokenSecret); + TwitterFactory tf = new TwitterFactory(cb.build()); + return tf.getInstance(); + } + + @Override + public void tweet(String text) { + try { + getTwitterInstance().updateStatus(text); + } catch (TwitterException e) { + //TODO: To implement how to deal with these kind of errors. + } + } +} diff --git a/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java b/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java new file mode 100644 index 0000000..6f8f1ec --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java @@ -0,0 +1,33 @@ +package tv.codely.mooc.notification.infrastructure; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import twitter4j.Twitter; +import twitter4j.TwitterException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class Twitter4JPublisherShould { + + Twitter4JPublisher publisher; + + Twitter twitterInstance; + + @BeforeEach + void setUp() { + publisher = spy(new Twitter4JPublisher("consumerKey", "consumerSecret", "accessToken", "accessTokenSecret")); + Twitter twitterInstance = mock(Twitter.class); + doReturn(twitterInstance).when(publisher).getTwitterInstance(); + } + + @Test + void post_tweet() throws TwitterException { + String text = "Text to tweet"; + + publisher.tweet(text); + + verify(twitterInstance).updateStatus(text); + } + +} \ No newline at end of file From 23c62128d120e3410208ff0a9286630cf2f68068 Mon Sep 17 00:00:00 2001 From: marcoslop Date: Sun, 10 Jan 2021 18:39:59 +0100 Subject: [PATCH 4/4] Event to process errors and notify them when twitterpublisher fails --- .../application/ProcessErrorGenerated.java | 22 +++++++++++++ .../mooc/errors/domain/ErrorGenerated.java | 18 +++++++++++ .../mooc/errors/domain/ErrorProcessor.java | 7 ++++ .../ErrorProcessorSystemErr.java | 11 +++++++ .../create/SendTweetOnVideoPublished.java | 12 ++++++- .../notification/domain/TwitterException.java | 8 +++++ .../notification/domain/TwitterPublisher.java | 2 +- .../infrastructure/Twitter4JPublisher.java | 10 ++++-- .../VideoPublisherCliController.java | 10 ++++-- .../ProcessErrorGeneratedTest.java | 32 +++++++++++++++++++ .../SendTweetOnVideoPublishedShould.java | 24 +++++++++++--- .../Twitter4JPublisherShould.java | 16 ++++++++-- .../infrastructure/bus/ReactorEventBus.java | 4 +++ 13 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 src/mooc/main/tv/codely/mooc/errors/application/ProcessErrorGenerated.java create mode 100644 src/mooc/main/tv/codely/mooc/errors/domain/ErrorGenerated.java create mode 100644 src/mooc/main/tv/codely/mooc/errors/domain/ErrorProcessor.java create mode 100644 src/mooc/main/tv/codely/mooc/errors/infrastructure/ErrorProcessorSystemErr.java create mode 100644 src/mooc/main/tv/codely/mooc/notification/domain/TwitterException.java create mode 100644 src/mooc/test/tv/codely/mooc/errors/application/ProcessErrorGeneratedTest.java diff --git a/src/mooc/main/tv/codely/mooc/errors/application/ProcessErrorGenerated.java b/src/mooc/main/tv/codely/mooc/errors/application/ProcessErrorGenerated.java new file mode 100644 index 0000000..cfc913d --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/errors/application/ProcessErrorGenerated.java @@ -0,0 +1,22 @@ +package tv.codely.mooc.errors.application; + +import lombok.AllArgsConstructor; +import tv.codely.mooc.errors.domain.ErrorGenerated; +import tv.codely.mooc.errors.domain.ErrorProcessor; +import tv.codely.shared.application.DomainEventSubscriber; + +@AllArgsConstructor +public class ProcessErrorGenerated implements DomainEventSubscriber { + + ErrorProcessor errorProcessor; + + @Override + public Class subscribedTo() { + return ErrorGenerated.class; + } + + @Override + public void consume(ErrorGenerated event) { + errorProcessor.processError(event); + } +} diff --git a/src/mooc/main/tv/codely/mooc/errors/domain/ErrorGenerated.java b/src/mooc/main/tv/codely/mooc/errors/domain/ErrorGenerated.java new file mode 100644 index 0000000..554e3c1 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/errors/domain/ErrorGenerated.java @@ -0,0 +1,18 @@ +package tv.codely.mooc.errors.domain; + +import lombok.Value; +import tv.codely.shared.domain.DomainEvent; + +@Value +public class ErrorGenerated implements DomainEvent { + + String errorMessage; + Throwable cause; + + private static final String FULL_QUALIFIED_EVENT_NAME = "codelytv.errors.error.generated"; + + @Override + public String fullQualifiedEventName() { + return FULL_QUALIFIED_EVENT_NAME; + } +} diff --git a/src/mooc/main/tv/codely/mooc/errors/domain/ErrorProcessor.java b/src/mooc/main/tv/codely/mooc/errors/domain/ErrorProcessor.java new file mode 100644 index 0000000..6f20f6f --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/errors/domain/ErrorProcessor.java @@ -0,0 +1,7 @@ +package tv.codely.mooc.errors.domain; + +public interface ErrorProcessor { + + void processError (ErrorGenerated error); + +} diff --git a/src/mooc/main/tv/codely/mooc/errors/infrastructure/ErrorProcessorSystemErr.java b/src/mooc/main/tv/codely/mooc/errors/infrastructure/ErrorProcessorSystemErr.java new file mode 100644 index 0000000..1af47d5 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/errors/infrastructure/ErrorProcessorSystemErr.java @@ -0,0 +1,11 @@ +package tv.codely.mooc.errors.infrastructure; + +import tv.codely.mooc.errors.domain.ErrorGenerated; +import tv.codely.mooc.errors.domain.ErrorProcessor; + +public class ErrorProcessorSystemErr implements ErrorProcessor { + @Override + public void processError(ErrorGenerated error) { + System.err.println(error.getErrorMessage() + ":" + error.getCause()); + } +} diff --git a/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java b/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java index 7d442b0..dfc71dd 100644 --- a/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java +++ b/src/mooc/main/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublished.java @@ -1,14 +1,20 @@ package tv.codely.mooc.notification.application.create; import lombok.AllArgsConstructor; +import tv.codely.mooc.errors.domain.ErrorGenerated; +import tv.codely.mooc.notification.domain.TwitterException; import tv.codely.mooc.notification.domain.TwitterPublisher; import tv.codely.mooc.video.domain.VideoPublished; import tv.codely.shared.application.DomainEventSubscriber; +import tv.codely.shared.domain.EventBus; + +import static java.util.Arrays.asList; @AllArgsConstructor public class SendTweetOnVideoPublished implements DomainEventSubscriber { TwitterPublisher publisher; + EventBus eventBus; @Override public Class subscribedTo() { @@ -17,6 +23,10 @@ public Class subscribedTo() { @Override public void consume(VideoPublished event) { - publisher.tweet("New video published: " + event.title()); + try { + publisher.tweet("New video published: " + event.title()); + } catch (TwitterException e) { + eventBus.publish(asList(new ErrorGenerated("Error tweeting after video published", e))); + } } } diff --git a/src/mooc/main/tv/codely/mooc/notification/domain/TwitterException.java b/src/mooc/main/tv/codely/mooc/notification/domain/TwitterException.java new file mode 100644 index 0000000..843dad4 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/domain/TwitterException.java @@ -0,0 +1,8 @@ +package tv.codely.mooc.notification.domain; + +public class TwitterException extends Exception{ + + public TwitterException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java b/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java index 33778b7..b058064 100644 --- a/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java +++ b/src/mooc/main/tv/codely/mooc/notification/domain/TwitterPublisher.java @@ -2,5 +2,5 @@ public interface TwitterPublisher { - void tweet (String text); + void tweet (String text) throws TwitterException; } diff --git a/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java b/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java index f809645..7b3588d 100644 --- a/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java +++ b/src/mooc/main/tv/codely/mooc/notification/infrastructure/Twitter4JPublisher.java @@ -26,11 +26,15 @@ protected Twitter getTwitterInstance() { } @Override - public void tweet(String text) { + public void tweet(String text) throws tv.codely.mooc.notification.domain.TwitterException { + tweet(text, getTwitterInstance()); + } + + private void tweet(String text, Twitter twitterInstance) throws tv.codely.mooc.notification.domain.TwitterException { try { - getTwitterInstance().updateStatus(text); + twitterInstance.updateStatus(text); } catch (TwitterException e) { - //TODO: To implement how to deal with these kind of errors. + throw new tv.codely.mooc.notification.domain.TwitterException("Error updating status " + text, e); } } } diff --git a/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java b/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java index f0e4f7f..820923e 100644 --- a/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java +++ b/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoPublisherCliController.java @@ -1,12 +1,14 @@ package tv.codely.mooc.video.infrastructure; +import tv.codely.mooc.errors.application.ProcessErrorGenerated; +import tv.codely.mooc.errors.domain.ErrorProcessor; +import tv.codely.mooc.errors.infrastructure.ErrorProcessorSystemErr; import tv.codely.mooc.notification.application.create.SendPushToSubscribersOnVideoPublished; import tv.codely.mooc.notification.application.create.SendTweetOnVideoPublished; import tv.codely.mooc.notification.domain.TwitterPublisher; import tv.codely.mooc.notification.infrastructure.FakeTwitterPublisher; import tv.codely.mooc.video.application.publish.VideoPublisher; import tv.codely.shared.application.DomainEventSubscriber; -import tv.codely.shared.domain.EventBus; import tv.codely.shared.infrastructure.bus.ReactorEventBus; import java.util.Set; @@ -14,11 +16,13 @@ public class VideoPublisherCliController { public static void main(String[] args) { final TwitterPublisher twitterPublisher = new FakeTwitterPublisher(); + final ErrorProcessor errorProcessor = new ErrorProcessorSystemErr(); final Set subscribers = Set.of( new SendPushToSubscribersOnVideoPublished(), - new SendTweetOnVideoPublished(twitterPublisher) + new ProcessErrorGenerated(errorProcessor) ); - final EventBus eventBus = new ReactorEventBus(subscribers); + final ReactorEventBus eventBus = new ReactorEventBus(subscribers); + eventBus.addSubscriber(new SendTweetOnVideoPublished(twitterPublisher, eventBus)); final var videoPublisher = new VideoPublisher(eventBus); final var videoTitle = "\uD83C\uDF89 New YouTube.com/CodelyTV video title"; diff --git a/src/mooc/test/tv/codely/mooc/errors/application/ProcessErrorGeneratedTest.java b/src/mooc/test/tv/codely/mooc/errors/application/ProcessErrorGeneratedTest.java new file mode 100644 index 0000000..7f29f62 --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/errors/application/ProcessErrorGeneratedTest.java @@ -0,0 +1,32 @@ +package tv.codely.mooc.errors.application; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tv.codely.mooc.errors.domain.ErrorGenerated; +import tv.codely.mooc.errors.domain.ErrorProcessor; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class ProcessErrorGeneratedTest { + + ProcessErrorGenerated processErrorGenerated; + + ErrorProcessor errorProcessor; + + @BeforeEach + void setUp() { + errorProcessor = mock(ErrorProcessor.class); + processErrorGenerated = new ProcessErrorGenerated(errorProcessor); + } + + @Test + void consume() { + ErrorGenerated errorEvent = new ErrorGenerated("error", new IllegalArgumentException("")); + + processErrorGenerated.consume(errorEvent); + + verify(errorProcessor).processError(errorEvent); + } +} \ No newline at end of file diff --git a/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java b/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java index fcc75eb..af1c5a5 100644 --- a/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java +++ b/src/mooc/test/tv/codely/mooc/notification/application/create/SendTweetOnVideoPublishedShould.java @@ -2,30 +2,46 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import tv.codely.mooc.errors.domain.ErrorGenerated; +import tv.codely.mooc.notification.domain.TwitterException; import tv.codely.mooc.notification.domain.TwitterPublisher; import tv.codely.mooc.video.domain.VideoPublished; +import tv.codely.shared.domain.EventBus; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import static java.util.Arrays.asList; +import static org.mockito.Mockito.*; class SendTweetOnVideoPublishedShould { SendTweetOnVideoPublished sendTweetOnVideoPublished; TwitterPublisher publisher; + EventBus eventBus; @BeforeEach void setUp() { publisher = mock(TwitterPublisher.class); - sendTweetOnVideoPublished = new SendTweetOnVideoPublished(publisher); + eventBus = mock(EventBus.class); + sendTweetOnVideoPublished = new SendTweetOnVideoPublished(publisher, eventBus); } @Test - void consume_should_send_text_to_twitter() { + void consume_should_send_text_to_twitter() throws TwitterException { VideoPublished videoPublished = new VideoPublished("title", "description"); sendTweetOnVideoPublished.consume(videoPublished); verify(publisher).tweet("New video published: " + videoPublished.title()); } + + @Test + void consume_should_send_notify_error_if_exception_tweeting() throws TwitterException { + VideoPublished videoPublished = new VideoPublished("title", "description"); + TwitterException exception = new TwitterException("error", new IllegalArgumentException("")); + doThrow(exception).when(publisher).tweet(anyString()); + + sendTweetOnVideoPublished.consume(videoPublished); + + verify(eventBus).publish(asList(new ErrorGenerated("Error tweeting after video published", exception))); + } } \ No newline at end of file diff --git a/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java b/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java index 6f8f1ec..437a045 100644 --- a/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java +++ b/src/mooc/test/tv/codely/mooc/notification/infrastructure/Twitter4JPublisherShould.java @@ -5,7 +5,7 @@ import twitter4j.Twitter; import twitter4j.TwitterException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; class Twitter4JPublisherShould { @@ -16,13 +16,13 @@ class Twitter4JPublisherShould { @BeforeEach void setUp() { + twitterInstance = mock(Twitter.class); publisher = spy(new Twitter4JPublisher("consumerKey", "consumerSecret", "accessToken", "accessTokenSecret")); - Twitter twitterInstance = mock(Twitter.class); doReturn(twitterInstance).when(publisher).getTwitterInstance(); } @Test - void post_tweet() throws TwitterException { + void post_tweet() throws tv.codely.mooc.notification.domain.TwitterException, TwitterException { String text = "Text to tweet"; publisher.tweet(text); @@ -30,4 +30,14 @@ void post_tweet() throws TwitterException { verify(twitterInstance).updateStatus(text); } + @Test + void post_tweet_with_error() throws TwitterException { + String text = "Text to tweet"; + doThrow(new TwitterException("Error")).when(twitterInstance).updateStatus(text); + + assertThrows(tv.codely.mooc.notification.domain.TwitterException.class, () -> { + publisher.tweet(text); + }); + } + } \ No newline at end of file diff --git a/src/shared/main/tv.codely.shared/infrastructure/bus/ReactorEventBus.java b/src/shared/main/tv.codely.shared/infrastructure/bus/ReactorEventBus.java index 13bfad9..4dcf571 100644 --- a/src/shared/main/tv.codely.shared/infrastructure/bus/ReactorEventBus.java +++ b/src/shared/main/tv.codely.shared/infrastructure/bus/ReactorEventBus.java @@ -21,6 +21,10 @@ public ReactorEventBus(final Set subscribers) { subscribers.forEach(this::registerOnEventBus); } + public void addSubscriber (DomainEventSubscriber subscriber) { + registerOnEventBus(subscriber); + } + @Override public void publish(final List events) { events.forEach(this::publish);