Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions examples/game-of-life.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@
app = Flask(__name__)


# Board width and height. We assume a square board for now.
# 45 crashes. Viceroy will pass us no more than 1936 bytes of the board. (Or
# maybe the entire URL gets truncated at 1965b.) If you change this, change the
# f"{i:010000b}" format string below to be the new value squared.
# Board width and height. We assume a square board for now. If you change this,
# change the f"{i:010000b}" format string below to be the new value squared.
WIDTH = HEIGHT = 50


def decompressed_board(compressed: str) -> str:
"""Decompress the board representation sent from JS, returning a B&W board
string ("10011011"...).

Viceroy will pass us no more than 1936 bytes of the board. (Or maybe the
entire URL gets truncated at 1965b.) This overcomes that (for the board
sizes we're interested in).

:arg compressed: A urlsafe_b64encode()d representation of the bit-packed
black-and-white board. (We don't need color info in order to compute the
next board.)
Expand All @@ -41,9 +43,8 @@ def decompressed_board(compressed: str) -> str:

@app.route("/board/<compressed_board>")
def board(compressed_board: str):
"""Return the next frame of the Game Of Life, given the current one. If a ""
board is given, return a new random board.
"""
"""Return the next frame of the Game Of Life, given the current one. If "none"
is given instead, return a new random board."""
cells = decompressed_board(compressed_board)

# Random board on start:
Expand Down
2 changes: 2 additions & 0 deletions fastly_compute/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ def handle(self, request: Any, body: Any) -> None:
# Something went wrong.
raise
else:
if not result:
break
request, body = result
serve_wsgi_request(
request,
Expand Down
6 changes: 3 additions & 3 deletions tests/test_app.py → tests/test_bottle_example.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Tests for the Fastly Compute Python service (app.wasm functionality)."""

from fastly_compute.testing import ViceroyTestBase


class TestFastlyComputeApp(ViceroyTestBase):
class TestBottleApp(ViceroyTestBase):
"""Tests for the Bottle framework example"""

def test_hello_endpoint(self):
"""Test the hello endpoint returns expected content."""
response = self.get("/hello/test")
Expand Down
4 changes: 2 additions & 2 deletions tests/test_flask_example.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Tests for the Flask example application."""
"""Tests for the Flask example application"""

from fastly_compute.testing import ViceroyTestBase


class TestFlaskApp(ViceroyTestBase):
"""Integration tests for the Flask example application."""
"""Integration tests for the Flask example application"""

WASM_FILE = "build/flask-app.composed.wasm"

Expand Down
50 changes: 50 additions & 0 deletions tests/test_game_of_life_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import re
from time import sleep

from fastly_compute.testing import ViceroyTestBase


class TestGameOfLife(ViceroyTestBase):
"""Integration tests for the Game Of Life example"""

WASM_FILE = "build/game-of-life.composed.wasm"

def test_root(self):
"""Show that the page full of JS at least loads."""
response = self.get("/")
assert response.status_code == 200
assert "async function startAnimation" in response.text

def test_random_board(self):
"""Show that random boards are generated for the first frame."""
response = self.get("/board/none")
assert response.status_code == 200
assert re.match(r"[01]+", response.text)

def test_evolved_board(self):
"""Show that a new board is correctly computed from an old one."""
response = self.get(
"/board/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAEAAAAAAABAAAAAHAAQAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAKAAAAAAAEgAAAAAAAwAADAAAAAAAN6AAAAAACscAAAAAAoOAGAAAAGACBgAAAAAAgAAAAAAAgAAAAAAAsAAAAAAAIAwAAAAAAgSAAAAAAAEgAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAQAAAAAAAOADAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
)
assert response.status_code == 200
assert (
response.text
== "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000001210000000000000000000000000000000002000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000202000000000000000000000000000000000000000000000020020000000000000000000000000000000000000000000000022000000000000000000010010000000000000000000000000000000000000000000231000300110000000000000000000000000000000000000003030001100020000000000000000000000000000000000000020300000200100000000033000000000000000000000000000032000000100000000000330000000000000000000000000000000000000000100000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000001100000022000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000020020000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000232000000000003300000000000000000000000000000000000100000000000033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
)

def test_reuse_sandboxes(self):
"""Make sure attempting to issue multiple requests to a single sandbox doesn't crash.

This does not test whether a single sandbox actually served multiple
requests, though it tries to provoke that. Still, 2 sandboxes could have
served 1 request each.
"""
response = self.get("/board/none")
assert response.status_code == 200
response = self.get("/board/none")
assert response.status_code == 200

# Reports about crashers in the post-response code come *after* the
# request has succeeded. And it seems to take awhile to show up.
sleep(0.5) # .3 is not enough.
assert "WebAssembly trapped" not in "\n".join(self.server.output_lines)