// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// VMOptions=
// VMOptions=--short_socket_read
// VMOptions=--short_socket_write
// VMOptions=--short_socket_read --short_socket_write

import "package:expect/expect.dart";
import "dart:async";
import "dart:io";
import "dart:typed_data";
import "dart:math";

testClientAndServerCloseNoListen(int connections) {
  HttpServer.bind("127.0.0.1", 0).then((server) {
    int closed = 0;
    server.listen((request) {
      request.response.close();
      request.response.done.then((_) {
        closed++;
        if (closed == connections) {
          Expect.equals(0, server.connectionsInfo().active);
          Expect.equals(
            server.connectionsInfo().total,
            server.connectionsInfo().idle,
          );
          server.close();
        }
      });
    });
    var client = HttpClient();
    for (int i = 0; i < connections; i++) {
      client
          .get("127.0.0.1", server.port, "/")
          .then((request) => request.close())
          .then((response) {});
    }
  });
}

testClientCloseServerListen(int connections) {
  HttpServer.bind("127.0.0.1", 0).then((server) {
    int closed = 0;
    check() {
      closed++;
      if (closed == connections * 2) {
        Expect.equals(0, server.connectionsInfo().active);
        Expect.equals(
          server.connectionsInfo().total,
          server.connectionsInfo().idle,
        );
        server.close();
      }
    }

    server.listen((request) {
      request.listen(
        (_) {},
        onDone: () {
          request.response.close();
          request.response.done.then((_) => check());
        },
      );
    });
    var client = HttpClient();
    for (int i = 0; i < connections; i++) {
      client
          .get("127.0.0.1", server.port, "/")
          .then((request) => request.close())
          .then((response) => check());
    }
  });
}

testClientCloseSendingResponse(int connections) {
  var buffer = Uint8List(64 * 1024);
  var rand = Random();
  for (int i = 0; i < buffer.length; i++) {
    buffer[i] = rand.nextInt(256);
  }
  HttpServer.bind("127.0.0.1", 0).then((server) {
    int closed = 0;
    check() {
      closed++;
      // Wait for both server and client to see the connections as closed.
      if (closed == connections * 2) {
        Expect.equals(0, server.connectionsInfo().active);
        Expect.equals(
          server.connectionsInfo().total,
          server.connectionsInfo().idle,
        );
        server.close();
      }
    }

    server.listen((request) {
      var timer = Timer.periodic(const Duration(milliseconds: 50), (_) {
        request.response.add(buffer);
      });
      request.response.done.catchError((_) {}).whenComplete(() {
        check();
        timer.cancel();
      });
    });
    var client = HttpClient();
    for (int i = 0; i < connections; i++) {
      client
          .get("127.0.0.1", server.port, "/")
          .then((request) => request.close())
          .then((response) {
            // Ensure we don't accept the response until we have send the entire
            // request.
            var subscription = response.listen((_) {});
            Timer(const Duration(milliseconds: 20), () {
              subscription.cancel();
              check();
            });
          });
    }
  });
}

// Closing the request early, before sending the full request payload should
// result in an error on both server and client.
testClientCloseWhileSendingRequest(int connections) {
  HttpServer.bind("127.0.0.1", 0).then((server) {
    int serverErrors = 0;
    int clientErrors = 0;
    server.listen(
      (request) {
        request.listen(
          (_) {},
          onError: (_) {
            serverErrors++;
            if (serverErrors == connections) {
              server.close();
            }
          },
        );
      },
      onDone: () {
        Expect.equals(connections, clientErrors);
        Expect.equals(connections, serverErrors);
      },
    );
    var client = HttpClient();
    for (int i = 0; i < connections; i++) {
      Future<HttpClientResponse?>.value(
        client.post("127.0.0.1", server.port, "/").then((request) {
          request.contentLength = 110;
          request.write("0123456789");
          return request.close();
        }),
      ).catchError((_) {
        clientErrors++;
      });
    }
  });
}

main() {
  testClientAndServerCloseNoListen(10);
  testClientCloseServerListen(10);
  testClientCloseSendingResponse(10);
  testClientCloseWhileSendingRequest(10);
}
