🎨 Reduce dependency on Node’s fields
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Aug 2022 10:15:00 +0000 (12:15 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Aug 2022 11:06:57 +0000 (13:06 +0200)
Using fields is getting increasingly hard to mock with more recent Java
versions. This change moves some of the necessary field access to the
dependency injection configuration so it’s restricted to a single place in the
source code and tests don’t have to mess with this.

src/main/java/net/pterodactylus/sone/core/FreenetInterface.java
src/main/kotlin/net/pterodactylus/sone/freenet/HighLevelSimpleClientCreator.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/main/FreenetModule.kt
src/test/kotlin/net/pterodactylus/sone/core/FreenetInterfaceTest.kt
src/test/kotlin/net/pterodactylus/sone/main/FreenetModuleTest.kt
src/test/kotlin/net/pterodactylus/sone/main/SonePluginTest.kt
src/test/kotlin/net/pterodactylus/sone/test/FreenetObjects.kt [new file with mode: 0644]

index e77badf..59e790c 100644 (file)
@@ -66,6 +66,7 @@ import freenet.client.async.ClientPutCallback;
 import freenet.client.async.ClientPutter;
 import freenet.client.async.SnoopMetadata;
 import freenet.client.async.USKCallback;
+import freenet.client.async.USKManager;
 import freenet.keys.FreenetURI;
 import freenet.keys.InsertableClientSSK;
 import freenet.keys.USK;
@@ -93,6 +94,8 @@ public class FreenetInterface {
 
        /** The node to interact with. */
        private final Node node;
+       private final USKManager uskManager;
+       private final ClientContext clientContext;
 
        private final SoneUriCreator soneUriCreator;
 
@@ -110,11 +113,13 @@ public class FreenetInterface {
        private final RequestClient imageLoader = new RequestClientBuilder().realTime().build();
 
        @Inject
-       public FreenetInterface(EventBus eventBus, Node node, SoneUriCreator soneUriCreator) {
+       public FreenetInterface(EventBus eventBus, Node node, USKManager uskManager, ClientContext clientContext, SoneUriCreator soneUriCreator, HighLevelSimpleClientCreator highLevelSimpleClientCreator) {
                this.eventBus = eventBus;
                this.node = node;
+               this.uskManager = uskManager;
+               this.clientContext = clientContext;
                this.soneUriCreator = soneUriCreator;
-               this.client = node.clientCore.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS, false, true);
+               this.client = highLevelSimpleClientCreator.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS, false, true);
        }
 
        //
@@ -186,7 +191,7 @@ public class FreenetInterface {
                try {
                        ClientGetter clientGetter = client.fetch(uri, 2097152, callback, fetchContext, RequestStarter.INTERACTIVE_PRIORITY_CLASS);
                        clientGetter.setMetaSnoop(snoop);
-                       clientGetter.restart(uri, fetchContext.filterData, node.clientCore.clientContext);
+                       clientGetter.restart(uri, fetchContext.filterData, clientContext);
                } catch (FetchException fe) {
                        /* stupid exception that can not actually be thrown! */
                }
@@ -254,7 +259,7 @@ public class FreenetInterface {
                        USKCallback uskCallback) {
                try {
                        soneUskCallbacks.put(FreenetURIsKt.getRoutingKeyString(requestUri), uskCallback);
-                       node.clientCore.uskManager.subscribe(create(requestUri),
+                       uskManager.subscribe(create(requestUri),
                                        uskCallback, true, requestClient);
                } catch (MalformedURLException mue1) {
                        logger.log(WARNING, format("Could not subscribe USK “%s”!",
@@ -266,9 +271,7 @@ public class FreenetInterface {
                        USKCallback uskCallback) {
                try {
                        soneUskCallbacks.put(FreenetURIsKt.getRoutingKeyString(requestUri), uskCallback);
-                       node.clientCore
-                                       .uskManager
-                                       .subscribe(create(requestUri), uskCallback, false, requestClient);
+                       uskManager.subscribe(create(requestUri), uskCallback, false, requestClient);
                } catch (MalformedURLException mue1) {
                        logger.log(WARNING,
                                        format("Could not subscribe USK “%s”!", requestUri),
@@ -291,7 +294,7 @@ public class FreenetInterface {
                logger.log(Level.FINEST, String.format("USKs left: %d", soneUskCallbacks.size()));
                uskCallbacks.forEach(uskCallback -> {
                        try {
-                               node.clientCore.uskManager.unsubscribe(USK.create(soneUriCreator.getRequestUri(sone)), uskCallback);
+                               uskManager.unsubscribe(USK.create(soneUriCreator.getRequestUri(sone)), uskCallback);
                        } catch (MalformedURLException mue1) {
                                logger.log(Level.FINE, String.format("Could not unsubscribe USK “%s”!", soneUriCreator.getRequestUri(sone)), mue1);
                        }
@@ -327,7 +330,7 @@ public class FreenetInterface {
 
                };
                try {
-                       node.clientCore.uskManager.subscribe(USK.create(uri), uskCallback, true, requestClient);
+                       uskManager.subscribe(USK.create(uri), uskCallback, true, requestClient);
                        uriUskCallbacks.put(USK.create(uri).clearCopy().getURI(), uskCallback);
                } catch (MalformedURLException mue1) {
                        logger.log(Level.WARNING, String.format("Could not subscribe to USK: %s", uri), mue1);
@@ -347,7 +350,7 @@ public class FreenetInterface {
                                logger.log(Level.INFO, String.format("Could not unregister unknown USK: %s", uri));
                                return;
                        }
-                       node.clientCore.uskManager.unsubscribe(USK.create(uri), uskCallback);
+                       uskManager.unsubscribe(USK.create(uri), uskCallback);
                } catch (MalformedURLException mue1) {
                        logger.log(Level.INFO, String.format("Could not unregister invalid USK: %s", uri), mue1);
                }
@@ -435,7 +438,7 @@ public class FreenetInterface {
                 */
                @SuppressWarnings("synthetic-access")
                public void cancel() {
-                       clientPutter.cancel(node.clientCore.clientContext);
+                       clientPutter.cancel(clientContext);
                        eventBus.post(new ImageInsertAbortedEvent(image));
                        bucket.free();
                }
diff --git a/src/main/kotlin/net/pterodactylus/sone/freenet/HighLevelSimpleClientCreator.kt b/src/main/kotlin/net/pterodactylus/sone/freenet/HighLevelSimpleClientCreator.kt
new file mode 100644 (file)
index 0000000..0874838
--- /dev/null
@@ -0,0 +1,17 @@
+package net.pterodactylus.sone.freenet
+
+import freenet.client.HighLevelSimpleClient
+import freenet.node.NodeClientCore
+
+fun interface HighLevelSimpleClientCreator {
+
+       fun makeClient(prioClass: Short, forceDontIgnoreTooManyPathComponents: Boolean, realTimeFlag: Boolean): HighLevelSimpleClient
+
+}
+
+class DefaultHighLevelSimpleClientCreator(private val nodeClientCore: NodeClientCore) : HighLevelSimpleClientCreator {
+
+       override fun makeClient(prioClass: Short, forceDontIgnoreTooManyPathComponents: Boolean, realTimeFlag: Boolean): HighLevelSimpleClient =
+               nodeClientCore.makeClient(prioClass, forceDontIgnoreTooManyPathComponents, realTimeFlag)
+
+}
index 1438c2a..691ae4e 100644 (file)
@@ -2,9 +2,13 @@ package net.pterodactylus.sone.main
 
 import com.google.inject.*
 import freenet.client.*
+import freenet.client.async.ClientContext
+import freenet.client.async.USKManager
 import freenet.clients.http.*
 import freenet.node.*
 import freenet.pluginmanager.*
+import net.pterodactylus.sone.freenet.DefaultHighLevelSimpleClientCreator
+import net.pterodactylus.sone.freenet.HighLevelSimpleClientCreator
 import net.pterodactylus.sone.freenet.plugin.*
 import javax.inject.Provider
 import javax.inject.Singleton
@@ -27,4 +31,20 @@ class FreenetModule(private val pluginRespirator: PluginRespirator) : Module {
        @Singleton
        fun getSessionManager() = pluginRespirator.getSessionManager("Sone")!!
 
+       @Provides
+       fun getNodeClientCore(node: Node): NodeClientCore =
+               node.clientCore
+
+       @Provides
+       fun getHighLevelSimpleClientCreator(nodeClientCore: NodeClientCore): HighLevelSimpleClientCreator =
+               DefaultHighLevelSimpleClientCreator(nodeClientCore)
+
+       @Provides
+       fun getClientContext(nodeClientCore: NodeClientCore): ClientContext =
+               nodeClientCore.clientContext
+
+       @Provides
+       fun getUskManager(nodeClientCore: NodeClientCore): USKManager =
+               nodeClientCore.uskManager
+
 }
index 9cbaff0..ffd5c60 100644 (file)
@@ -51,7 +51,7 @@ class FreenetInterfaceTest {
        @Suppress("UnstableApiUsage")
        private val eventBus = mock<EventBus>()
        private val node = mock<Node>()
-       private val nodeClientCore = mock<NodeClientCore>()
+       private val clientContext = mock<ClientContext>()
        private val highLevelSimpleClient: HighLevelSimpleClient = mock(HighLevelSimpleClient::class.java, withSettings().extraInterfaces(RequestClient::class.java))
        private val randomSource = DummyRandomSource()
        private val uskManager = mock<USKManager>()
@@ -69,12 +69,8 @@ class FreenetInterfaceTest {
        private val freenetInterface: FreenetInterface
 
        init {
-               whenever(nodeClientCore.makeClient(anyShort(), anyBoolean(), anyBoolean())).thenReturn(highLevelSimpleClient)
-               setField(node, "clientCore", nodeClientCore)
                setField(node, "random", randomSource)
-               setField(nodeClientCore, "uskManager", uskManager)
-               setField(nodeClientCore, "clientContext", mock<ClientContext>())
-               freenetInterface = FreenetInterface(eventBus, node, soneUriCreator)
+               freenetInterface = FreenetInterface(eventBus, node, uskManager, clientContext, soneUriCreator) { _, _, _ -> highLevelSimpleClient }
                insertToken = freenetInterface.InsertToken(image)
                insertToken.setBucket(bucket)
        }
index c6aed88..84cb567 100644 (file)
@@ -2,9 +2,12 @@ package net.pterodactylus.sone.main
 
 import com.google.inject.*
 import freenet.client.*
+import freenet.client.async.ClientContext
+import freenet.client.async.USKManager
 import freenet.clients.http.*
 import freenet.node.*
 import freenet.pluginmanager.*
+import net.pterodactylus.sone.freenet.HighLevelSimpleClientCreator
 import net.pterodactylus.sone.freenet.plugin.*
 import net.pterodactylus.sone.test.*
 import org.hamcrest.MatcherAssert.*
@@ -24,10 +27,18 @@ class FreenetModuleTest {
        val expectedException = ExpectedException.none()!!
 
        private val sessionManager = mock<SessionManager>()
+       private val uskManager = mock<USKManager>()
+       private val clientContext = mock<ClientContext>()
        private val pluginRespirator = deepMock<PluginRespirator>().apply {
                whenever(getSessionManager("Sone")).thenReturn(sessionManager)
        }
-       private val node = pluginRespirator.node!!
+       private val nodeClientCore = mock<NodeClientCore>().also {
+               setField(it, "uskManager", uskManager)
+               setField(it, "clientContext", clientContext)
+       }
+       private val node = pluginRespirator.node!!.also {
+               setField(it, "clientCore", nodeClientCore)
+       }
        private val highLevelSimpleClient = pluginRespirator.hlSimpleClient!!
        private val toadletContainer: ToadletContainer = pluginRespirator.toadletContainer
        private val pageMaker: PageMaker = pluginRespirator.pageMaker
@@ -113,4 +124,19 @@ class FreenetModuleTest {
                injector.verifySingletonInstance<PluginConnector>()
        }
 
+       @Test
+       fun `high level simple client creator is returned correctly`() {
+               assertThat(injector.getInstance<HighLevelSimpleClientCreator>(), notNullValue());
+       }
+
+       @Test
+       fun `client context is returned correctly`() {
+               assertThat(injector.getInstance<ClientContext>(), sameInstance(clientContext))
+       }
+
+       @Test
+       fun `usk manager is returned correctly`() {
+               assertThat(injector.getInstance<USKManager>(), sameInstance(uskManager))
+       }
+
 }
index a656702..3983aa2 100644 (file)
@@ -38,6 +38,7 @@ class SonePluginTest {
                setField(node, "clientCore", clientCore)
                whenever(pluginRespirator.node).thenReturn(node)
                setField(clientCore, "uskManager", uskManager)
+               setField(clientCore, "clientContext", mock<ClientContext>())
        }
 
        @Test
diff --git a/src/test/kotlin/net/pterodactylus/sone/test/FreenetObjects.kt b/src/test/kotlin/net/pterodactylus/sone/test/FreenetObjects.kt
new file mode 100644 (file)
index 0000000..9c14658
--- /dev/null
@@ -0,0 +1,8 @@
+package net.pterodactylus.sone.test
+
+import freenet.client.HighLevelSimpleClient
+import net.pterodactylus.sone.freenet.HighLevelSimpleClientCreator
+
+val dummyHighLevelSimpleClient = deepMock<HighLevelSimpleClient>()
+
+val dummyHighLevelSimpleClientCreator: HighLevelSimpleClientCreator = HighLevelSimpleClientCreator { _, _, _ -> dummyHighLevelSimpleClient }