Code cleanup, introduce event bus tests

This commit is contained in:
Andrea Cavalli 2021-11-18 00:12:45 +01:00
parent 139971f459
commit a47b56a07e
13 changed files with 120 additions and 142 deletions

View File

@ -1,72 +0,0 @@
package io.volvox.td;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import it.tdlight.common.Init;
import it.tdlight.common.utils.CantLoadLibrary;
import it.tdlight.jni.TdApi;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class JacksonTdObjectJsonSerializer implements TdObjectJsonSerializer {
private final ObjectMapper objectMapper;
static {
try {
Init.start();
} catch (CantLoadLibrary e) {
throw new RuntimeException(e);
}
}
public JacksonTdObjectJsonSerializer() {
var objectMapper = new ObjectMapper();
var validator = BasicPolymorphicTypeValidator.builder();
// Iterate TdApi inner classes
for (Class<?> declaredClass : TdApi.class.getDeclaredClasses()) {
// Register only TDLib objects
if (TdApi.Object.class.isAssignableFrom(declaredClass)) {
if (Modifier.isAbstract(declaredClass.getModifiers())) {
// Register abstract base type
objectMapper.addMixIn(declaredClass, AbstractTypeMixIn.class);
validator.allowIfBaseType(declaredClass);
} else {
// Register named subtype
validator.allowIfSubType(declaredClass);
objectMapper.registerSubtypes(new NamedType(declaredClass, declaredClass.getSimpleName()));
}
}
}
this.objectMapper = objectMapper;
}
@Override
public TdApi.Object deserialize(InputStream json) {
try {
return objectMapper.readValue(json, TdApi.Object.class);
} catch (IOException e) {
throw new UnsupportedOperationException(e);
}
}
@Override
public String serialize(TdApi.Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new UnsupportedOperationException(e);
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
public abstract static class AbstractTypeMixIn {}
}

View File

@ -1,19 +0,0 @@
package io.volvox.td;
import java.util.UUID;
import javax.enterprise.context.Dependent;
@Dependent
public class RandomUUID {
final String uuid;
public RandomUUID() {
this.uuid = UUID.randomUUID().toString();
}
@Override
public String toString() {
return uuid;
}
}

View File

@ -6,6 +6,7 @@ import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Update; import it.tdlight.jni.TdApi.Update;
public interface TdClient { public interface TdClient {
Multi<Update> updates(); Multi<Update> updates();
<T extends TdApi.Object> Uni<T> send(TdApi.Function<T> function); <T extends TdApi.Object> Uni<T> send(TdApi.Function<T> function);

View File

@ -70,9 +70,9 @@ public class TdEventBusClient implements TdClient {
} }
@ConsumeEvent(value = "td.send", codec = TdObjectCodec.class) @ConsumeEvent(value = "td.send", codec = TdObjectCodec.class)
public void onSendRequest(Message<TdObject> msg) { public void onSendRequest(Message<TdObjectCodec.TdObject> msg) {
this.send(msg.body().getObject()).subscribe().with(message -> msg.reply(message, SEND_OPTS), ex -> { this.send(msg.body().getObject()).subscribe().with(message -> msg.reply(message, SEND_OPTS), ex -> {
if (ex instanceof TdException tdException) { if (ex instanceof TelegramException tdException) {
msg.fail(tdException.getCode(), tdException.getMessage()); msg.fail(tdException.getCode(), tdException.getMessage());
} else { } else {
msg.fail(500, ex.toString()); msg.fail(500, ex.toString());

View File

@ -1,6 +1,5 @@
package io.volvox.td; package io.volvox.td;
import io.quarkus.runtime.StartupEvent;
import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import it.tdlight.common.ReactiveTelegramClient; import it.tdlight.common.ReactiveTelegramClient;
@ -59,7 +58,7 @@ public class TdNativeClient implements TdClient {
.transformToUni(item -> { .transformToUni(item -> {
if (item.getConstructor() == Error.CONSTRUCTOR) { if (item.getConstructor() == Error.CONSTRUCTOR) {
TdApi.Error error = (TdApi.Error) item; TdApi.Error error = (TdApi.Error) item;
return Uni.createFrom().failure(new TdException(error.code, error.message)); return Uni.createFrom().failure(new TelegramException(error.code, error.message));
} else { } else {
return Uni.createFrom().item(item); return Uni.createFrom().item(item);
} }
@ -75,7 +74,7 @@ public class TdNativeClient implements TdClient {
.transformToUni(item -> { .transformToUni(item -> {
if (item.getConstructor() == Error.CONSTRUCTOR) { if (item.getConstructor() == Error.CONSTRUCTOR) {
TdApi.Error error = (TdApi.Error) item; TdApi.Error error = (TdApi.Error) item;
return Uni.createFrom().failure(new TdException(error.code, error.message)); return Uni.createFrom().failure(new TelegramException(error.code, error.message));
} else { } else {
return Uni.createFrom().item(item); return Uni.createFrom().item(item);
} }

View File

@ -1,18 +0,0 @@
package io.volvox.td;
import it.tdlight.jni.TdApi;
@SuppressWarnings("CdiInjectionPointsInspection")
public class TdObject {
private final TdApi.Object object;
public TdObject(TdApi.Object object) {
this.object = object;
}
public <T extends TdApi.Object> T getObject() {
//noinspection unchecked
return (T) object;
}
}

View File

@ -5,10 +5,9 @@ import io.vertx.core.eventbus.MessageCodec;
import it.tdlight.jni.TdApi; import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Deserializer; import it.tdlight.jni.TdApi.Deserializer;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
import javax.inject.Singleton;
@ApplicationScoped @ApplicationScoped
public class TdObjectCodec implements MessageCodec<TdObject, TdObject> { public class TdObjectCodec implements MessageCodec<TdObjectCodec.TdObject, TdObjectCodec.TdObject> {
@Override public void encodeToWire(Buffer buffer, TdObject t) { @Override public void encodeToWire(Buffer buffer, TdObject t) {
BufferUtils.encode(buffer, out -> t.getObject().serialize(out)); BufferUtils.encode(buffer, out -> t.getObject().serialize(out));
@ -33,4 +32,18 @@ public class TdObjectCodec implements MessageCodec<TdObject, TdObject> {
// Always "-1" // Always "-1"
return -1; return -1;
} }
public static class TdObject {
private final TdApi.Object object;
public TdObject(TdApi.Object object) {
this.object = object;
}
public <T extends TdApi.Object> T getObject() {
//noinspection unchecked
return (T) object;
}
}
} }

View File

@ -1,11 +1,70 @@
package io.volvox.td; package io.volvox.td;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import it.tdlight.common.Init;
import it.tdlight.common.utils.CantLoadLibrary;
import it.tdlight.jni.TdApi; import it.tdlight.jni.TdApi;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Modifier;
import javax.enterprise.context.ApplicationScoped;
public interface TdObjectJsonSerializer { @ApplicationScoped
public class TdObjectJsonSerializer {
TdApi.Object deserialize(InputStream json); private final ObjectMapper objectMapper;
String serialize(TdApi.Object object); static {
try {
Init.start();
} catch (CantLoadLibrary e) {
throw new RuntimeException(e);
}
}
public TdObjectJsonSerializer() {
var objectMapper = new ObjectMapper();
var validator = BasicPolymorphicTypeValidator.builder();
// Iterate TdApi inner classes
for (Class<?> declaredClass : TdApi.class.getDeclaredClasses()) {
// Register only TDLib objects
if (TdApi.Object.class.isAssignableFrom(declaredClass)) {
if (Modifier.isAbstract(declaredClass.getModifiers())) {
// Register abstract base type
objectMapper.addMixIn(declaredClass, AbstractTypeMixIn.class);
validator.allowIfBaseType(declaredClass);
} else {
// Register named subtype
validator.allowIfSubType(declaredClass);
objectMapper.registerSubtypes(new NamedType(declaredClass, declaredClass.getSimpleName()));
}
}
}
this.objectMapper = objectMapper;
}
public TdApi.Object deserialize(InputStream json) {
try {
return objectMapper.readValue(json, TdApi.Object.class);
} catch (IOException e) {
throw new UnsupportedOperationException(e);
}
}
public String serialize(TdApi.Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new UnsupportedOperationException(e);
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
public abstract static class AbstractTypeMixIn {}
} }

View File

@ -4,8 +4,6 @@ import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.vertx.ConsumeEvent; import io.quarkus.vertx.ConsumeEvent;
import io.vertx.core.eventbus.EventBus; import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message; import io.vertx.core.eventbus.Message;
import it.tdlight.tdnative.NativeClient;
import it.tdlight.tdnative.NativeLog;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -29,7 +27,7 @@ public class TdService {
Instance<TdEventBusClient> sessionInstances; Instance<TdEventBusClient> sessionInstances;
@ConsumeEvent(value = "td.start-session") @ConsumeEvent(value = "td.start-session")
private void onStartSession(Message<String> msg) { public void onStartSession(Message<String> msg) {
var sessionId = this.startSession(); var sessionId = this.startSession();
msg.reply(sessionId); msg.reply(sessionId);
} }

View File

@ -1,17 +1,11 @@
package io.volvox.td; package io.volvox.td;
import io.quarkus.runtime.StartupEvent;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import it.tdlight.jni.TdApi; import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Function; import it.tdlight.jni.TdApi.Function;
import it.tdlight.jni.TdApi.Object; import it.tdlight.jni.TdApi.Object;
import java.io.InputStream; import java.io.InputStream;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Objects;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.inject.Inject; import javax.inject.Inject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.POST; import javax.ws.rs.POST;

View File

@ -1,11 +1,11 @@
package io.volvox.td; package io.volvox.td;
public class TdException extends Exception { public class TelegramException extends Exception {
private final int code; private final int code;
private final String message; private final String message;
public TdException(int code, String message) { public TelegramException(int code, String message) {
super(code + ": " + message); super(code + ": " + message);
this.code = code; this.code = code;
this.message = message; this.message = message;

View File

@ -0,0 +1,30 @@
package io.volvox.td;
import io.quarkus.test.junit.QuarkusTest;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.helpers.test.UniAssertSubscriber;
import io.vertx.mutiny.core.eventbus.EventBus;
import io.vertx.mutiny.core.eventbus.Message;
import java.util.UUID;
import javax.inject.Inject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class TdEventBusTest {
@Inject
EventBus bus;
@Test
public void testStartSession() {
Uni<String> uni = bus.<String>request("td.start-session", null).map(Message::body);
UniAssertSubscriber<String> subscriber = uni.subscribe().withSubscriber(UniAssertSubscriber.create());
String item = subscriber.awaitItem().assertCompleted().getItem();
Assertions.assertNotNull(item);
Assertions.assertDoesNotThrow(() -> UUID.fromString(item));
}
}

View File

@ -1,22 +1,15 @@
package io.volvox.td; package io.volvox.td;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.specification.Argument;
import java.util.List;
import java.util.Set;
import org.hamcrest.CoreMatchers;
import org.hamcrest.core.IsNot;
import org.hamcrest.text.IsEmptyString;
import org.hamcrest.text.MatchesPattern;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.text.IsEmptyString.emptyOrNullString; import static org.hamcrest.text.IsEmptyString.emptyOrNullString;
import io.quarkus.test.junit.QuarkusTest;
import java.util.Set;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest @QuarkusTest
public class TdResourceTest { public class TdResourceTest {