async-io-test.c++ 5.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "async-io.h"
#include "async-unix.h"
#include "debug.h"
#include <gtest/gtest.h>

namespace kj {
namespace {

TEST(AsyncIo, SimpleNetwork) {
  UnixEventLoop loop;
Kenton Varda's avatar
Kenton Varda committed
34
  auto network = Network::newSystemNetwork();
35 36 37 38 39 40 41 42 43

  Own<ConnectionReceiver> listener;
  Own<AsyncIoStream> server;
  Own<AsyncIoStream> client;

  char receiveBuffer[4];

  auto port = newPromiseAndFulfiller<uint>();

44 45 46 47 48 49 50
  loop.daemonize(port.promise.then([&](uint portnum) {
    return network->parseRemoteAddress("127.0.0.1", portnum);
  }).then([&](Own<RemoteAddress>&& result) {
    return result->connect();
  }).then([&](Own<AsyncIoStream>&& result) {
    client = kj::mv(result);
    return client->write("foo", 3);
51 52
  }));

53 54 55 56 57 58 59 60 61 62 63
  kj::String result = network->parseLocalAddress("*").then([&](Own<LocalAddress>&& result) {
    listener = result->listen();
    port.fulfiller->fulfill(listener->getPort());
    return listener->accept();
  }).then([&](Own<AsyncIoStream>&& result) {
    server = kj::mv(result);
    return server->tryRead(receiveBuffer, 3, 4);
  }).then([&](size_t n) {
    EXPECT_EQ(3u, n);
    return heapString(receiveBuffer, n);
  }).wait();
64 65 66 67 68

  EXPECT_EQ("foo", result);
}

String tryParseLocal(EventLoop& loop, Network& network, StringPtr text, uint portHint = 0) {
69
  return network.parseLocalAddress(text, portHint).wait()->toString();
70 71 72
}

String tryParseRemote(EventLoop& loop, Network& network, StringPtr text, uint portHint = 0) {
73
  return network.parseRemoteAddress(text, portHint).wait()->toString();
74 75 76 77
}

TEST(AsyncIo, AddressParsing) {
  UnixEventLoop loop;
Kenton Varda's avatar
Kenton Varda committed
78 79 80 81 82 83 84 85 86 87 88 89
  auto network = Network::newSystemNetwork();

  EXPECT_EQ("*:0", tryParseLocal(loop, *network, "*"));
  EXPECT_EQ("*:123", tryParseLocal(loop, *network, "123"));
  EXPECT_EQ("*:123", tryParseLocal(loop, *network, ":123"));
  EXPECT_EQ("[::]:123", tryParseLocal(loop, *network, "0::0", 123));
  EXPECT_EQ("0.0.0.0:0", tryParseLocal(loop, *network, "0.0.0.0"));
  EXPECT_EQ("1.2.3.4:5678", tryParseRemote(loop, *network, "1.2.3.4", 5678));
  EXPECT_EQ("[12ab:cd::34]:321", tryParseRemote(loop, *network, "[12ab:cd:0::0:34]:321", 432));

  EXPECT_EQ("unix:foo/bar/baz", tryParseLocal(loop, *network, "unix:foo/bar/baz"));
  EXPECT_EQ("unix:foo/bar/baz", tryParseRemote(loop, *network, "unix:foo/bar/baz"));
90 91
}

92 93 94 95 96 97
TEST(AsyncIo, OneWayPipe) {
  UnixEventLoop loop;

  auto pipe = newOneWayPipe();
  char receiveBuffer[4];

98
  loop.daemonize(pipe.out->write("foo", 3));
99

100 101 102 103
  kj::String result = pipe.in->tryRead(receiveBuffer, 3, 4).then([&](size_t n) {
    EXPECT_EQ(3u, n);
    return heapString(receiveBuffer, n);
  }).wait();
104 105 106 107 108 109 110 111 112 113 114

  EXPECT_EQ("foo", result);
}

TEST(AsyncIo, TwoWayPipe) {
  UnixEventLoop loop;

  auto pipe = newTwoWayPipe();
  char receiveBuffer1[4];
  char receiveBuffer2[4];

115 116 117 118 119
  auto promise = pipe.ends[0]->write("foo", 3).then([&]() {
    return pipe.ends[0]->tryRead(receiveBuffer1, 3, 4);
  }).then([&](size_t n) {
    EXPECT_EQ(3u, n);
    return heapString(receiveBuffer1, n);
120 121
  });

122 123 124 125 126 127
  kj::String result = pipe.ends[1]->write("bar", 3).then([&]() {
    return pipe.ends[1]->tryRead(receiveBuffer2, 3, 4);
  }).then([&](size_t n) {
    EXPECT_EQ(3u, n);
    return heapString(receiveBuffer2, n);
  }).wait();
128

129
  kj::String result2 = promise.wait();
130 131 132 133 134

  EXPECT_EQ("foo", result);
  EXPECT_EQ("bar", result2);
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
TEST(AsyncIo, RunIoEventLoop) {
  auto pipe = newOneWayPipe();
  char receiveBuffer[4];

  String result = runIoEventLoop([&]() {
    auto promise1 = pipe.out->write("foo", 3);

    auto promise2 = pipe.in->tryRead(receiveBuffer, 3, 4)
      .then([&](size_t n) {
        EXPECT_EQ(3u, n);
        return heapString(receiveBuffer, n);
      });

    return promise1.then(mvCapture(promise2, [](Promise<String> promise2) { return promise2; }));
  });

  EXPECT_EQ("foo", result);
}

154 155
}  // namespace
}  // namespace kj