-- when a socket is being closed, while another coroutine
-- is reading on it, the `select` call does not return an event on that
-- socket. Hence the loop keeps running until the watch-dog kicks-in, reads
-- on the socket, and that returns the final "closed" error to the reading
-- coroutine.
--
-- when a socket is closed, any read/write operation should return immediately
-- with a "closed" error.

local copas = require "copas"
local socket = require "socket"

copas.loop(function()

  local client_socket
  local close_time
  local send_end_time
  local receive_end_time

  print "------------- starting close test ---------------"

  local function check_exit()
    if receive_end_time and send_end_time then
      -- both set, so we're done
      print "success!"
      os.exit(0)
    end
  end


  do -- set up a server that accepts but doesn't read or write anything
    local server = socket.bind("localhost", 20000)

    copas.addserver(server, copas.handler(function(conn_skt)
      -- client connected, we're not doing anything, let the client
      -- wait in the read/write queues
      copas.pause(2)
      -- now we're closing the connecting_socket
      close_time = copas.gettime()
      print("closing client socket now, client receive and send operation should immediately error out now")
      client_socket:close()

      copas.pause(10)
      conn_skt:close()
      copas.removeserver(server)
      print "timeout, test failed"
      os.exit(1)
    end))
  end


  do -- create a client that connect to the server
    client_socket = copas.wrap(socket.connect("localhost", 20000))

    copas.addthread(function()
      local data, err = client_socket:receive(1)
      print("receive result: ", tostring(data), tostring(err))
      receive_end_time = copas.gettime()
      print("receive took: ", receive_end_time - close_time)
      check_exit()
    end)

    copas.addthread(function()
      local ok, err = true, nil
      while ok do -- loop to fill any buffers, until we get stuck
        ok, err = client_socket:send(("hello world"):rep(100))
      end
      print("send result: ", tostring(ok), tostring(err))
      send_end_time = copas.gettime()
      print("send took: ", send_end_time - close_time)
      check_exit()
    end)
  end

end)
