-- tests improvement

This commit is contained in:
jacek.wolniewicz
2024-07-05 13:21:59 +02:00
parent e40bde8e7c
commit aa56f8eaea
8 changed files with 165 additions and 114 deletions

View File

@@ -26,17 +26,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface TikTokEventObserver { public @interface TikTokEventObserver
{
/** /**
* When more than one method listen for certain Even, you can specify the method priority * When more than one method listen for certain Event, you can specify the method priority
* @return * @see Priority
*/ */
Priority priority() default Priority.NORMAL; Priority priority() default Priority.NORMAL;
/** /**
* When true, action is invoked on the another thread * When true, action is invoked on a thread, from the threads pool
* @return
*/ */
boolean async() default false; boolean async() default false;
} }

View File

@@ -32,10 +32,11 @@ import java.util.function.Consumer;
public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> { public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
/** /**
* This method is triggered after default mappings are registered * This method is triggered after default mappings are registered
* It could be used to OVERRIDE behaviour of mappings and implement custom behaviour * It could be used to OVERRIDE behaviour of mappings and implement custom behaviour
* * <p>
* Be aware if for example you override WebcastGiftEvent, onGiftEvent() will not be working * Be aware if for example you override WebcastGiftEvent, onGiftEvent() will not be working
* *
* @param onCustomMappings lambda method * @param onCustomMappings lambda method
@@ -43,18 +44,22 @@ public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
*/ */
LiveClientBuilder mappings(Consumer<LiveMapper> onCustomMappings); LiveClientBuilder mappings(Consumer<LiveMapper> onCustomMappings);
@Deprecated(forRemoval = true, since = "1.8.2 use `mappings` method instead")
LiveClientBuilder onMappings(Consumer<LiveMapper> onCustomMappings);
/** /**
* Configuration of client settings * Configuration of client settings
* @see LiveClientSettings *
* @param onConfigure * @param onConfigure
* @return * @return
* @see LiveClientSettings
*/ */
LiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure); LiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure);
/** /**
* Adding events listener class, its fancy way to register events without using lamda method * Adding events listener class, its fancy way to register events without using lamda method
* but actual method in class that implements TikTokEventListener * but actual method in class that implements TikTokEventListener
*
* @return * @return
*/ */
LiveClientBuilder addListener(Object listener); LiveClientBuilder addListener(Object listener);
@@ -64,7 +69,6 @@ public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
* Allows you to use own implementation of internal TikTokLive dependencies, * Allows you to use own implementation of internal TikTokLive dependencies,
* when the default implementation does not meet your needs * when the default implementation does not meet your needs
* *
*
* @param onCustomizeDependencies access to dependency container * @param onCustomizeDependencies access to dependency container
* @return * @return
*/ */
@@ -72,18 +76,19 @@ public interface LiveClientBuilder extends EventsBuilder<LiveClientBuilder> {
/** /**
* Builds new instance of the LiveClient * Builds new instance of the LiveClient
*
* @return LiveClient object * @return LiveClient object
*/ */
LiveClient build(); LiveClient build();
/** /**
* Builds new instance of the LiveClient and connects to live * Builds new instance of the LiveClient and connects to live
*
* @return LiveClient object * @return LiveClient object
*/ */
LiveClient buildAndConnect(); LiveClient buildAndConnect();
/** /**
*
* @return LiveClient object and connects to TikTok live asynchronously * @return LiveClient object and connects to TikTok live asynchronously
*/ */
CompletableFuture<LiveClient> buildAndConnectAsync(); CompletableFuture<LiveClient> buildAndConnectAsync();

View File

@@ -78,17 +78,6 @@ public class TikTokLiveClient implements LiveClient
this.logger = logger; this.logger = logger;
} }
public void connectAsync(Consumer<LiveClient> onConnection) {
connectAsync().thenAccept(onConnection);
}
public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() -> {
connect();
return this;
});
}
public void connect() { public void connect() {
try { try {
tryConnect(); tryConnect();
@@ -199,4 +188,15 @@ public class TikTokLiveClient implements LiveClient
messageHandler.handleSingleMessage(this, message); messageHandler.handleSingleMessage(this, message);
} }
public void connectAsync(Consumer<LiveClient> onConnection) {
connectAsync().thenAccept(onConnection);
}
public CompletableFuture<LiveClient> connectAsync() {
return CompletableFuture.supplyAsync(() -> {
connect();
return this;
});
}
} }

View File

@@ -70,6 +70,12 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
return this; return this;
} }
@Override
public LiveClientBuilder onMappings(Consumer<LiveMapper> onCustomMappings) {
mappings(onCustomMappings);
return this;
}
public TikTokLiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure) { public TikTokLiveClientBuilder configure(Consumer<LiveClientSettings> onConfigure) {
onConfigure.accept(clientSettings); onConfigure.accept(clientSettings);
return this; return this;

View File

@@ -25,6 +25,7 @@ package io.github.jwdeveloper.tiktok.listener;
import io.github.jwdeveloper.dependance.api.DependanceContainer; import io.github.jwdeveloper.dependance.api.DependanceContainer;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException; import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
@@ -40,14 +41,14 @@ import java.util.concurrent.atomic.AtomicReference;
public class TikTokListenersManager implements ListenersManager { public class TikTokListenersManager implements ListenersManager {
private final Map<Object, List<ListenerMethodInfo>> listeners; private final Map<Object, List<ListenerMethodInfo>> listeners;
private final LiveEventsHandler eventObserver; private final LiveEventsHandler eventsHandler;
private final ExecutorService executorService; private final ExecutorService executorService;
private final DependanceContainer dependanceContainer; private final DependanceContainer dependanceContainer;
public TikTokListenersManager(LiveEventsHandler tikTokEventHandler, public TikTokListenersManager(LiveEventsHandler tikTokEventHandler,
DependanceContainer dependanceContainer) { DependanceContainer dependanceContainer) {
this.eventObserver = tikTokEventHandler; this.eventsHandler = tikTokEventHandler;
this.dependanceContainer = dependanceContainer; this.dependanceContainer = dependanceContainer;
this.listeners = new HashMap<>(); this.listeners = new HashMap<>();
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
@@ -66,7 +67,7 @@ public class TikTokListenersManager implements ListenersManager {
var methodsInfo = getMethodsInfo(listener); var methodsInfo = getMethodsInfo(listener);
for (var methodInfo : methodsInfo) { for (var methodInfo : methodsInfo) {
eventObserver.subscribe(methodInfo.getEventType(), methodInfo.getAction()); eventsHandler.subscribe(methodInfo.getEventType(), methodInfo.getAction());
} }
listeners.put(listener, methodsInfo); listeners.put(listener, methodsInfo);
} }
@@ -78,7 +79,7 @@ public class TikTokListenersManager implements ListenersManager {
} }
var methodsInfo = listeners.get(listener); var methodsInfo = listeners.get(listener);
for (var methodInfo : methodsInfo) { for (var methodInfo : methodsInfo) {
eventObserver.unsubscribe(methodInfo.getEventType(), methodInfo.getAction()); eventsHandler.unsubscribe(methodInfo.getEventType(), methodInfo.getAction());
} }
listeners.remove(listener); listeners.remove(listener);
} }
@@ -149,7 +150,7 @@ public class TikTokListenersManager implements ListenersManager {
var parameters = methodContainer.resolveParameters(method); var parameters = methodContainer.resolveParameters(method);
method.invoke(listener, parameters); method.invoke(listener, parameters);
} catch (Exception e) { } catch (Exception e) {
throw new TikTokEventListenerMethodException(e); eventsHandler.publish(liveClient, new TikTokErrorEvent(new TikTokEventListenerMethodException(e)));
} }
}; };
} }

View File

@@ -1,110 +1,51 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.requests.LiveData; import io.github.jwdeveloper.dependance.implementation.DependanceContainerBuilder;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.data.events.TikTokConnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.control.TikTokPreConnectionEvent;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokRoomDataResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.room.TikTokRoomInfoEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.http.LiveHttpClient; import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.LiveMessagesHandler;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.websocket.LiveSocketClient;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito;
import java.util.logging.Logger; public class TikTokLiveClientTests extends TikTokTestBase {
public class TikTokLiveClientTests { @Override
public void onBeforeEachTest(LiveClientBuilder liveClientBuilder,
DependanceContainerBuilder containerBuilder) {
private LiveClient sut; liveClientBuilder.onMappings()
LiveMessagesHandler messageHandler;
GiftsManager giftsManager;
TikTokRoomInfo tikTokLiveMeta;
LiveHttpClient tiktokHttpClient;
LiveSocketClient webSocketClient;
LiveEventsHandler tikTokEventHandler;
LiveClientSettings clientSettings;
ListenersManager listenersManager;
Logger logger;
@Before
public void onBefore() {
messageHandler = Mockito.mock(LiveMessagesHandler.class);
giftsManager = Mockito.mock(GiftsManager.class);
tikTokLiveMeta = Mockito.mock(TikTokRoomInfo.class);
tiktokHttpClient = Mockito.mock(LiveHttpClient.class);
webSocketClient = Mockito.mock(LiveSocketClient.class);
tikTokEventHandler = Mockito.mock(LiveEventsHandler.class);
clientSettings = Mockito.mock(LiveClientSettings.class);
listenersManager = Mockito.mock(ListenersManager.class);
logger = Mockito.mock(Logger.class);
sut = new TikTokLiveClient(messageHandler,
giftsManager,
tikTokLiveMeta,
tiktokHttpClient,
webSocketClient,
tikTokEventHandler,
clientSettings,
listenersManager,
logger);
} }
@Test @Test
public void shouldThrownWhenAlreadyConnected() { public void shouldThrownWhenAlreadyConnected() {
tikTokLiveMeta.setConnectionState(ConnectionState.CONNECTED); roomInfoMock().setConnectionState(ConnectionState.CONNECTED);
Assert.assertThrows(TikTokLiveException.class, () -> Assert.assertThrows(TikTokLiveException.class, () ->
{ {
sut.connect(); liveClient().connect();
}); });
Assert.assertEquals(ConnectionState.DISCONNECTED, roomInfoMock().getConnectionState());
AssertEvents(
TikTokErrorEvent.class,
TikTokDisconnectedEvent.class
);
} }
@Test
public void shouldThrowWhenUserIsOffline() {
var request = new LiveData.Request("X");
var response = new LiveData.Response();
response.setLiveStatus(LiveData.LiveStatus.HostOffline);
Mockito.when(tiktokHttpClient.fetchLiveData(request)).thenReturn(response);
Assert.assertThrows(TikTokLiveException.class, () ->
{
sut.connect();
});
}
@Test
public void shouldThrowWhenUserNotFound()
{
var request = new LiveData.Request("X");
var response = new LiveData.Response();
response.setLiveStatus(LiveData.LiveStatus.HostNotFound);
Mockito.when(tiktokHttpClient.fetchLiveData(request)).thenReturn(response);
Assert.assertThrows(TikTokLiveException.class, () ->
{
sut.connect();
});
}
@Test
public void shouldThrowWhenAgeRestricted()
{
Mockito.when(tiktokHttpClient.fetchLiveData(new LiveData.Request("X")))
.thenReturn(new LiveData.Response());
Assert.assertThrows(TikTokLiveException.class, () ->
{
sut.connect();
});
}
@Test @Test
public void shouldConnect() { public void shouldConnect() {
// sut.connect(); liveClient().connect();
Assert.assertEquals(ConnectionState.CONNECTED, roomInfoMock().getConnectionState());
AssertEvents(
TikTokConnectingEvent.class,
TikTokRoomDataResponseEvent.class,
TikTokPreConnectionEvent.class,
TikTokConnectedEvent.class,
TikTokRoomInfoEvent.class);
} }
} }

View File

@@ -0,0 +1,53 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.dependance.implementation.DependanceContainerBuilder;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveEventsHandler;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.mocks.EventsHandlerMock;
import lombok.Getter;
import lombok.experimental.Accessors;
import org.junit.Before;
/**
* Base class for the unit tests
*/
@Getter
@Accessors(fluent = true)
public abstract class TikTokTestBase {
private LiveClient liveClient;
private EventsHandlerMock eventsHandlerMock;
private TikTokRoomInfo roomInfoMock;
public void AssertEvents(Class<? extends TikTokEvent>... events) {
eventsHandlerMock.assertEvents(events);
}
@Before
public void setup() {
var builder = TikTokLive.newClient("test");
eventsHandlerMock = new EventsHandlerMock();
roomInfoMock = new TikTokRoomInfo();
roomInfoMock.setHostName("test");
liveClient = builder
.configure(liveClientSettings ->
{
liveClientSettings.setOffline(true);
liveClientSettings.setFetchGifts(false);
})
.customize(containerBuilder ->
{
containerBuilder.registerSingleton(LiveEventsHandler.class, eventsHandlerMock);
containerBuilder.registerSingleton(TikTokRoomInfo.class, roomInfoMock);
onBeforeEachTest(builder, containerBuilder);
}).build();
}
public abstract void onBeforeEachTest(LiveClientBuilder liveClientBuilder, DependanceContainerBuilder containerBuilder);
}

View File

@@ -0,0 +1,46 @@
package io.github.jwdeveloper.tiktok.mocks;
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import java.util.ArrayList;
import java.util.List;
/**
* Cache published events,
*/
public class EventsHandlerMock extends TikTokLiveEventHandler {
private final List<TikTokEvent> publishedEvents = new ArrayList<TikTokEvent>();
@Override
public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
super.publish(tikTokLiveClient, tikTokEvent);
publishedEvents.add(tikTokEvent);
}
@SafeVarargs
public final void assertEvents(Class<? extends TikTokEvent>... events) {
if (events.length == 0 && !publishedEvents.isEmpty()) {
var classNames = publishedEvents.stream()
.map(e -> e.getClass().getSimpleName())
.toList();
var invokedEvents = String.join("\n", classNames);
throw new IllegalArgumentException("Not events should be invoked but there was: \n" + invokedEvents);
}
for (var i = 0; i < events.length; i++) {
var expectedEvent = events[i];
var invokedEvent = publishedEvents.get(i);
if (expectedEvent.equals(invokedEvent.getClass())) {
continue;
}
throw new RuntimeException("Expected event was " + expectedEvent + " but acctuall was " + invokedEvent.getClass());
}
}
}