about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--092socket.mu169
1 files changed, 43 insertions, 126 deletions
diff --git a/092socket.mu b/092socket.mu
index b1c08b6a..c6418c8d 100644
--- a/092socket.mu
+++ b/092socket.mu
@@ -1,70 +1,62 @@
-# Wrappers around socket primitives that take a 'local-network' object and are
-# thus easier to test.
-#
-# The current semantics of fake port-connections don't match UNIX socket ones,
-# but we'll improve them as we learn more.
+# Wrappers around socket primitives that are easier to test.
 
-container local-network [
-  data:&:@:port-connection
-]
-
-# Port connections represent connections to ports on localhost.
-# Before passing a local-network object to network functions
-# `start-reading-socket` and `start-writing-socket`, add port-connections to
-# the local-network.
-#
-# For reading, `receive-from-socket` will check for a
-# port-connection on the port parameter that's been passed in. If there's
-# no port-connection for that port, it will return nothing and log an error.
-# If there is a port-connection for that port, it will transmit the contents
-# to the provided sink.
-#
-# For writing, `start-writing-socket` returns a sink connecting the
-# caller to the socket on the passed-in port.
-container port-connection [
-  port:num
-  contents:text
-]
-
-def new-port-connection port:num, contents:text -> p:&:port-connection [
+# To test server operations, just run a real client against localhost.
+scenario example-server-test [
   local-scope
-  load-ingredients
-  p:&:port-connection <- new port-connection:type
-  *p <- merge port, contents
+  # test server without a fake on a random (real) port
+  # that way repeatedly running the test will give ports time to timeout and
+  # close before reusing them
+  make-random-nondeterministic
+  port:num <- random-in-range 0/real-random-numbers, 8000, 8100
+  run [
+    socket:num <- $open-server-socket port
+    assert socket, [ 
+F - example-server-test: $open-server-socket failed]
+    handler-routine:number <- start-running serve-one-request socket, example-handler
+  ]
+  source:&:source:char <- start-reading-from-network 0/real-resources, [localhost/], port
+  response:text <- drain source
+  10:@:char/raw <- copy *response
+  memory-should-contain [
+    10:array:character <- [abc]
+  ]
 ]
-
-def new-fake-network -> n:&:local-network [
+# helper just for this scenario
+def example-handler query:text -> response:text [
   local-scope
   load-ingredients
-  n:&:local-network <- new local-network:type
-  local-network-ports:&:@:port-connection <- new port-connection:type, 0
-  *n <- put *n, data:offset, local-network-ports
+  reply [abc]
 ]
 
-scenario write-to-fake-socket [
+type request-handler = (recipe text -> text)
+
+def serve-one-request socket:num, request-handler:request-handler [
   local-scope
-  single-port-network:&:local-network <- new-fake-network
-  sink:&:sink:char, writer:num/routine <- start-writing-socket single-port-network, 8080
-  sink <- write sink, 120/x
-  close sink
-  wait-for-routine writer
-  tested-port-connections:&:@:port-connection <- get *single-port-network, data:offset
-  tested-port-connection:port-connection <- index *tested-port-connections, 0
-  contents:text <- get tested-port-connection, contents:offset
-  10:@:char/raw <- copy *contents
-  memory-should-contain [
-    10:array:character <- [x]
-  ]
+  load-ingredients
+  session:num <- $accept socket
+  assert session, [ 
+F - example-server-test: $accept failed]
+  contents:&:source:char, sink:&:sink:char <- new-channel 30
+  sink <- start-running receive-from-socket session, sink
+  query:text <- drain contents
+  response:text <- call request-handler, query
+  write-to-socket session, response
+  $close-socket session
 ]
 
 def start-reading-from-network resources:&:resources, uri:text -> contents:&:source:char [
   local-scope
   load-ingredients
   {
+    port:num, port-found?:boolean <- next-ingredient
+    break-if port-found?
+    port <- copy 80/http-port
+  }
+  {
     break-if resources
     # real network
     host:text, path:text <- split-at uri, 47/slash
-    socket:num <- $open-client-socket host, 80/http-port
+    socket:num <- $open-client-socket host, port
     assert socket, [contents]
     req:text <- interpolate [GET _ HTTP/1.1], path
     request-socket socket, req
@@ -72,23 +64,7 @@ def start-reading-from-network resources:&:resources, uri:text -> contents:&:sou
     start-running receive-from-socket socket, sink
     return
   }
-  # fake network
-#?   i:num <- copy 0
-#?   data:&:@:resource <- get *fs, data:offset
-#?   len:num <- length *data
-#?   {
-#?     done?:bool <- greater-or-equal i, len
-#?     break-if done?
-#?     tmp:resource <- index *data, i
-#?     i <- add i, 1
-#?     curr-filename:text <- get tmp, name:offset
-#?     found?:bool <- equal filename, curr-filename
-#?     loop-unless found?
-#?     contents:&:source:char, sink:&:sink:char <- new-channel 30
-#?     curr-contents:text <- get tmp, contents:offset
-#?     start-running transmit-from-text curr-contents, sink
-#?     return
-#?   }
+  # todo: fake network
   return 0/not-found
 ]
 
@@ -103,65 +79,6 @@ def request-socket socket:num, s:text -> socket:num [
   $write-to-socket socket, 10/lf
 ]
 
-def start-writing-socket network:&:local-network, port:num -> sink:&:sink:char, routine-id:num [
-  local-scope
-  load-ingredients
-  source:&:source:char, sink:&:sink:char <- new-channel 30
-  {
-    break-if network
-    socket:num <- $open-server-socket port
-    session:num <- $accept socket
-    # TODO Create channel implementation of write-to-socket.
-    return sink, 0/routine-id
-  }
-  # fake network
-  routine-id <- start-running transmit-to-fake-socket network, port, source
-]
-
-def transmit-to-fake-socket network:&:local-network, port:num, source:&:source:char -> network:&:local-network, source:&:source:char [
-  local-scope
-  load-ingredients
-  # compute new port connection contents
-  buf:&:buffer <- new-buffer 30
-  {
-    c:char, done?:bool, source <- read source
-    break-unless c
-    buf <- append buf, c
-    break-if done?
-    loop
-  }
-  contents:text <- buffer-to-array buf
-  new-port-connection:&:port-connection <- new-port-connection port, contents
-  # Got the contents of the channel, time to write to fake port.
-  i:num <- copy 0
-  port-connections:&:@:port-connection <- get *network, data:offset
-  len:num <- length *port-connections
-  {
-    done?:bool <- greater-or-equal i, len
-    break-if done?
-    current:port-connection <- index *port-connections, i
-    current-port:num <- get current, port:offset
-    ports-match?:bool <- equal current-port, port
-    i <- add i, 1
-    loop-unless ports-match?
-    # Found an existing connection on this port, overwrite.
-    put-index *port-connections, i, *new-port-connection
-    reply
-  }
-  # Couldn't find an existing connection on this port, initialize a new one.
-  new-len:num <- add len, 1
-  new-port-connections:&:@:port-connection <- new port-connection:type, new-len
-  put *network, data:offset, new-port-connections
-  i:num <- copy 0
-  {
-    done?:bool <- greater-or-equal i, len
-    break-if done?
-    tmp:port-connection <- index *port-connections, i
-    put-index *new-port-connections, i, tmp
-  }
-  put-index *new-port-connections, len, *new-port-connection
-]
-
 def receive-from-socket socket:num, sink:&:sink:char -> sink:&:sink:char [
   local-scope
   load-ingredients