diff --git a/pom.xml b/pom.xml
index 6811152..7fc31f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -214,5 +214,22 @@ SOFTWARE.
2.4.8
test
+
+ com.jcabi
+ jcabi-http
+ 1.17.2
+
+
+ com.sun.grizzly
+ grizzly-servlet-webserver
+ 1.9.65
+ test
+
+
+ org.glassfish.jersey.core
+ jersey-common
+ 2.27
+ test
+
diff --git a/src/main/java/io/zold/api/RtRemote.java b/src/main/java/io/zold/api/RtRemote.java
new file mode 100644
index 0000000..3382c00
--- /dev/null
+++ b/src/main/java/io/zold/api/RtRemote.java
@@ -0,0 +1,95 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Yegor Bugayenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package io.zold.api;
+
+import com.jcabi.http.Request;
+import com.jcabi.http.request.JdkRequest;
+import java.io.IOException;
+import org.cactoos.text.FormattedText;
+import org.cactoos.text.UncheckedText;
+
+/**
+ * Default implementation of {@link Remote}.
+ * @since 1.0
+ */
+public final class RtRemote implements Remote {
+
+ /**
+ * Request to Node.
+ */
+ private final Request req;
+
+ /**
+ * Ctor.
+ * @param host Remote host
+ * @param port Remote port
+ */
+ public RtRemote(final String host, final int port) {
+ this.req = new JdkRequest(
+ new UncheckedText(
+ new FormattedText("http://%s:%d", host, port)
+ ).asString()
+ );
+ }
+
+ // @todo #38:30min Let us Implement RtRemote.score() here. When implemented,
+ // the unit test RemoteTest.scoreIsNotYetImplemented should be removed and
+ // replaced with an appropriate unit test.
+ @Override
+ public Score score() {
+ throw new UnsupportedOperationException("score() not yet supported");
+ }
+
+ // @todo #38:30min Implementation of push() is currently incomplete. We need
+ // to read the entire contents of Wallet and include it in the request body
+ // before fetching. Right now there's no way for us to do that. What I'm
+ // thinking is to add a new method in Wallet interface, Wallet.contents(),
+ // which reads the entire content of the Wallet and returns it. Then pass
+ // that the request body here.
+ @Override
+ public void push(final Wallet wallet) {
+ try {
+ this.req.uri().path(
+ new UncheckedText(
+ new FormattedText(
+ "wallets/%016x", wallet.id()
+ )
+ ).asString()
+ ).back().method("PUT")
+ .body().set("zold")
+ .back()
+ .fetch();
+ } catch (final IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ // @todo #38:30min Let us Implement RtRemote.pull() here. When implemented,
+ // the unit test RemoteTest.scoreIsNotYetImplemented should be removed and
+ // replaced with an appropriate unit test.
+ @Override
+ public Wallet pull(final long id) {
+ throw new UnsupportedOperationException("pull() not yet supported");
+ }
+}
diff --git a/src/test/java/io/zold/api/NetworkTest.java b/src/test/java/io/zold/api/NetworkTest.java
index dc7a969..22486f5 100644
--- a/src/test/java/io/zold/api/NetworkTest.java
+++ b/src/test/java/io/zold/api/NetworkTest.java
@@ -34,16 +34,12 @@
* Test case for {@link Network}.
*
* @since 0.1
- * @todo #5:30min Implement Remote interface. Remote Interface must be
- * implemented because Network depends on Remote behavior. Network.pull
- * needs to search all remotes for some wallet id and merge all found
- * wallets; Network.push must push a wallet to a remote based in remote.
* @checkstyle JavadocMethodCheck (500 lines)
*/
public final class NetworkTest {
@Test
- public void pushWalletToAllRemotes() {
+ public void pushWalletToAllRemotes() throws IOException {
final Remote highremote = Mockito.mock(Remote.class);
final Remote lowremote = Mockito.mock(Remote.class);
final Wallet wallet = Mockito.mock(Wallet.class);
diff --git a/src/test/java/io/zold/api/RemoteTest.java b/src/test/java/io/zold/api/RemoteTest.java
new file mode 100644
index 0000000..df39c23
--- /dev/null
+++ b/src/test/java/io/zold/api/RemoteTest.java
@@ -0,0 +1,82 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Yegor Bugayenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package io.zold.api;
+
+import com.jcabi.http.mock.MkAnswer;
+import com.jcabi.http.mock.MkContainer;
+import com.jcabi.http.mock.MkGrizzlyContainer;
+import com.jcabi.http.mock.MkQuery;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+/**
+ * Test case for {@link Remote}.
+ * @since 1.0
+ * @checkstyle JavadocMethod (500 lines)
+ */
+public final class RemoteTest {
+
+ // @todo #38:30min RtRemote should be able to handle different HTTP response
+ // codes. Here we test HTTP 202 Accepted. Other possible responses as per
+ // the white paper are 400 (if data is corrupt), 402 (if taxes are unpaid),
+ // and 304 (if content is the same as that in the node). Let's handle
+ // those responses and create new tests as well.
+ @Test
+ public void pushesWallet() throws IOException {
+ try (
+ final MkContainer container = new MkGrizzlyContainer().next(
+ new MkAnswer.Simple(HttpURLConnection.HTTP_ACCEPTED)
+ ).start()
+ ) {
+ final long id = 1000L;
+ new RtRemote(
+ container.home().getHost(), container.home().getPort()
+ ).push(new Wallet.Fake(id));
+ final MkQuery query = container.take();
+ MatcherAssert.assertThat(
+ query.uri().getPath(),
+ Matchers.containsString(
+ "wallets/00000000000003e8"
+ )
+ );
+ MatcherAssert.assertThat(
+ query.body(),
+ Matchers.containsString("zold")
+ );
+ }
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void scoreIsNotYetImplemented() {
+ new RtRemote("foo", 1).score();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void pullIsNotYetImplemented() {
+ new RtRemote("bar", 1).pull(1);
+ }
+}