interactive test is working

This commit is contained in:
Taeer Bar-Yam 2024-07-18 06:44:13 -04:00
parent 693e21b1a8
commit dab12bc2b8
4 changed files with 110 additions and 35 deletions

View file

@ -38,7 +38,8 @@ let
${optionalString corsRules.enable '' ${optionalString corsRules.enable ''
garage bucket allow --read --write --owner ${bucketArg} --key tmp garage bucket allow --read --write --owner ${bucketArg} --key tmp
aws --endpoint http://s3.garage.localhost:3900 s3api put-bucket-cors --bucket ${bucketArg} --cors-configuration ${corsRulesJSON} # TODO: endpoin-url should not be hard-coded
aws --region ${cfg.settings.s3_api.s3_region} --endpoint-url http://s3.garage.localhost:3900 s3api put-bucket-cors --bucket ${bucketArg} --cors-configuration ${corsRulesJSON}
garage bucket deny --read --write --owner ${bucketArg} --key tmp garage bucket deny --read --write --owner ${bucketArg} --key tmp
''} ''}
''; '';
@ -124,6 +125,7 @@ in {
}; };
config = { config = {
virtualisation.vmVariant = { config, ... }: {
virtualisation.diskSize = 2048; virtualisation.diskSize = 2048;
virtualisation.forwardPorts = [ virtualisation.forwardPorts = [
{ {
@ -139,6 +141,7 @@ in {
]; ];
environment.systemPackages = [ pkgs.minio-client pkgs.awscli ]; environment.systemPackages = [ pkgs.minio-client pkgs.awscli ];
};
networking.firewall.allowedTCPPorts = [ 3901 3902 ]; networking.firewall.allowedTCPPorts = [ 3901 3902 ];
services.garage = { services.garage = {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

BIN
tests/green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

View file

@ -1,7 +1,37 @@
{ pkgs, self }: { pkgs, self }:
let let
lib = pkgs.lib;
# python = pkgs.python310.withPackages (ps: with ps; [ requests aiokafka ]); # python = pkgs.python310.withPackages (ps: with ps; [ requests aiokafka ]);
rebuildableTest = import ./rebuildableTest.nix pkgs; rebuildableTest = import ./rebuildableTest.nix pkgs;
seleniumScript = pkgs.writers.writePython3Bin "selenium-script"
{
libraries = with pkgs.python3Packages; [ selenium ];
} ''
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
print(1)
options = Options()
options.add_argument("--headless")
# devtools don't show up in headless screenshots
# options.add_argument("-devtools")
service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}") # noqa: E501
driver = webdriver.Firefox(options=options, service=service)
driver.get("http://mastodon.localhost:55001/public/local")
# wait until the statuses load
WebDriverWait(driver, 90).until(
lambda x: x.find_element(By.CLASS_NAME, "status"))
# XXX: how do I save this to the derivation output?
driver.save_screenshot("/mastodon-screenshot.png")
driver.close()
'';
in in
rebuildableTest { rebuildableTest {
name = "test-mastodon-garage"; name = "test-mastodon-garage";
@ -10,13 +40,29 @@ rebuildableTest {
# skipTypeCheck = true; # skipTypeCheck = true;
nodes = { nodes = {
server = { server = {config, ...}: {
virtualisation.memorySize = lib.mkVMOverride 4096;
imports = [ self.nixosModules.garage self.nixosModules.mastodon ]; imports = [ self.nixosModules.garage self.nixosModules.mastodon ];
environment.systemPackages = with pkgs; [ toot ]; # TODO: pair down
environment.systemPackages = with pkgs; [
python3
firefox-unwrapped
geckodriver
toot
xh
seleniumScript
helix
imagemagick
];
environment.variables = {
POST_MEDIA = ./green.png;
AWS_ACCESS_KEY_ID = config.services.garage.ensureKeys.mastodon.id;
AWS_SECRET_ACCESS_KEY = config.services.garage.ensureKeys.mastodon.secret;
};
}; };
}; };
testScript = '' testScript = {nodes, ...}: ''
import re import re
import time import time
@ -26,33 +72,59 @@ rebuildableTest {
server.wait_for_unit("mastodon-web.service") server.wait_for_unit("mastodon-web.service")
# make sure mastodon is fully up and running before we interact with it # make sure mastodon is fully up and running before we interact with it
# TODO: is there a way to test for this?
time.sleep(180) time.sleep(180)
with subtest("Account creation"): with subtest("Account creation"):
account_creation_output = server.succeed("mastodon-tootctl accounts create test --email test@test.com --confirmed --approve") account_creation_output = server.succeed("mastodon-tootctl accounts create test --email test@test.com --confirmed --approve")
password_re = re.compile('New password: (.*)') password_match = re.match('.*New password: ([^\n]*).*', account_creation_output, re.S)
password_match = password_re.match(account_creation_output)
assert password_match is not None assert password_match is not None
password = password_match.groups()[0] password = password_match.group(1)
with subtest("TTY Login"):
server.wait_until_tty_matches("1", "login: ")
server.send_chars("root\n");
with subtest("Log in with toot"): with subtest("Log in with toot"):
# toot doesn't provide a way to just specify our login details as arguments, so we have to pretend we're typing them in at the prompt # toot doesn't provide a way to just specify our login details as arguments, so we have to pretend we're typing them in at the prompt
server.send_chars("toot login_ctl\n") server.send_chars("toot login_cli --instance http://mastodon.localhost:55001 --email test@test.com\n")
time.sleep(0.2) server.wait_until_tty_matches("1", "Password: ")
# Enter instance URL
server.send_chars("http://mastodon.localhost:55001\n")
time.sleep(0.2)
# Email
server.send_chars("test@test.com\n")
time.sleep(0.2)
# Password
server.send_chars(password + "\n") server.send_chars(password + "\n")
server.wait_until_tty_matches("1", "Successfully logged in.")
with subtest("Post an image"): with subtest("post text"):
server.succeed("toot post --media ${./fediversity.png}") server.succeed("echo 'hello mastodon' | toot post")
# TODO: I don't think there's a good way to test for whether the image visually shows up. with subtest("post image"):
# we can test for CORS headers using curl / xh server.succeed("toot post --media $POST_MEDIA")
# or **maybe** somehow read the javascript console?
with subtest("access garage"):
server.succeed("mc alias set garage http://s3.garage.localhost:3900 --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY")
server.succeed("mc ls garage/mastodon")
with subtest("access image in garage"):
image = server.succeed("mc find garage --regex original")
image = image.rstrip()
assert image != ""
server.succeed(f"mc cat {image} >/garage-image.webp")
garage_image_hash = server.succeed("identify -quiet -format '%#' /garage-image.webp")
image_hash = server.succeed("identify -quiet -format '%#' $POST_MEDIA")
assert garage_image_hash == image_hash
with subtest("Content security policy allows garage images"):
headers = server.succeed("xh -h http://masstodon.localhost:55001/public/local")
csp_match = re.match('^Content-Security-Policy: (.*)$', headers, re.M)
assert csp_match is not None
csp = csp_match.group(1)
# the content security policy should include the garage server
garage_csp = re.match(".*web\.garage\.localhost:3902.*", csp)
assert garage_csp is not None
with subtest("image displays"):
server.succeed("selenium-script")
server.copy_from_vm("/mastodon-screenshot.png", "")
displayed_colors = server.succeed("convert /mastodon-screenshot.png -define histogram:unique-colors=true -format %c histogram:info:")
# check that the green image displayed somewhere
re.match(".*#00FF00.*", displayed_colors, re.S)
''; '';
} }