From: Stefan Sperling Subject: add another email notification test case To: gameoftrees@openbsd.org Date: Fri, 14 Feb 2025 17:46:51 +0100 This adds a test case for email notification where a tag and modified file are sent to the server in the same operation. There was a problem with notifications when I sent the 0.109 tag in combination with a modified CHANGES file earlier today, where the gotd notify process died. However, this test does not (yet?) reproduce this particular issue. Each notifciation causes a separate invocation of got-notify-email and thus 2 connections are made in this test case. I needed to add another custom Perl server for this because the nc-based hacks cannot deal with multiple SMTP connections. This is too limited for testing non-basic scenarios so I would like to propose my smtp-server script for inclusion in the test suite. Does this smtp-server script look fine? It adds a dependency on yet another perl cpan module but this can easily be installed from packages. If this approach looks fine then I would like to replace the use of nc -l hacks in the other tests with this new script as well. ok? add email notification test case for tag creation + file modifiation M regress/gotd/README | 1+ 1- M regress/gotd/email_notification.sh | 109+ 0- A regress/gotd/smtp-server | 81+ 0- 3 files changed, 191 insertions(+), 1 deletion(-) commit - f8922f66df0a859909cd8cbbab47888484cd7472 commit + 24c03e0c37fedbf06c192be320272efbf5a92ba6 blob - 0709a766c3b43610a20290c1e889d0ba50846d4c blob + faa5431af74cec9f5cfa7792534d3554f94b6ad5 --- regress/gotd/README +++ regress/gotd/README @@ -51,7 +51,7 @@ sshd must be restarted for configuration changes to ta The server test suite can now be run from the top-level directory: - $ doas pkg_add git p5-http-daemon p5-digest-hmac + $ doas pkg_add git p5-http-daemon p5-digest-hmac p5-net-daemon $ doas make server-regress The suite must be started as root in order to be able to start and stop gotd. blob - a394b238427aae690c7afae614a4e0e6b9de122d blob + b006f86ca11e0d1c8226fdee8bd96e7d6dfee32f --- regress/gotd/email_notification.sh +++ regress/gotd/email_notification.sh @@ -631,6 +631,114 @@ test_file_empty() { test_done "$testroot" "$ret" } +test_tag_and_commit_created() { + local testroot=`test_init tag_and_commit_created 1` + + got clone -a -q ${GOTD_TEST_REPO_URL} $testroot/repo-clone + ret=$? + if [ $ret -ne 0 ]; then + echo "got clone failed unexpectedly" >&2 + test_done "$testroot" 1 + return 1 + fi + + got checkout -q $testroot/repo-clone $testroot/wt >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + echo "got checkout failed unexpectedly" >&2 + test_done "$testroot" 1 + return 1 + fi + + echo "change alpha" > $testroot/wt/alpha + (cd $testroot/wt && got commit -m 'make changes' > /dev/null) + local commit_id=`git_show_head $testroot/repo-clone` + local author_time=`git_show_author_time $testroot/repo-clone` + + got tag -r $testroot/repo-clone -m "new tag" 1.1 > /dev/null + local commit_id=`git_show_head $testroot/repo-clone` + local tagger_time=`git_show_tagger_time $testroot/repo-clone 1.1` + local tag_id=`got ref -r $testroot/repo-clone -l \ + | grep "^refs/tags/1.1" | tr -d ' ' | cut -d: -f2` + local short_tag_id=`trim_obj_id 12 $tag_id` + + ./smtp-server -p $GOTD_TEST_SMTP_PORT -r 2 \ + > $testroot/stdout 2>$testroot/stderr & + + sleep 1 # server starts up + + got send -t 1.1 -q -r $testroot/repo-clone + ret=$? + if [ $ret -ne 0 ]; then + echo "got send failed unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + + wait %1 # wait for smtp-server + + HOSTNAME=`hostname` + short_commit_id=`trim_obj_id 12 $commit_id` + + printf "HELO localhost\r\n" > $testroot/stdout.expected + printf "MAIL FROM:<${GOTD_USER}@${HOSTNAME}>\r\n" \ + >> $testroot/stdout.expected + printf "RCPT TO:<${GOTD_DEVUSER}>\r\n" >> $testroot/stdout.expected + printf "DATA\r\n" >> $testroot/stdout.expected + printf "From: ${GOTD_USER}@${HOSTNAME}\r\n" >> $testroot/stdout.expected + printf "To: ${GOTD_DEVUSER}\r\n" >> $testroot/stdout.expected + printf "Subject: $GOTD_TEST_REPO_NAME: " >> $testroot/stdout.expected + printf "${GOTD_DEVUSER} created refs/tags/1.1: $short_tag_id\r\n" \ + >> $testroot/stdout.expected + printf "\r\n" >> $testroot/stdout.expected + printf "tag refs/tags/1.1\n" >> $testroot/stdout.expected + printf "from: $GOT_AUTHOR\n" >> $testroot/stdout.expected + d=`date -u -r $tagger_time +"%a %b %e %X %Y UTC"` + printf "date: $d\n" >> $testroot/stdout.expected + printf "object: commit $commit_id\n" >> $testroot/stdout.expected + printf "messagelen: 9\n" >> $testroot/stdout.expected + printf " \n" >> $testroot/stdout.expected + printf " new tag\n \n" >> $testroot/stdout.expected + printf "\r\n" >> $testroot/stdout.expected + printf ".\r\n" >> $testroot/stdout.expected + printf "QUIT\r\n" >> $testroot/stdout.expected + printf "HELO localhost\r\n" >> $testroot/stdout.expected + printf "MAIL FROM:<${GOTD_USER}@${HOSTNAME}>\r\n" \ + >> $testroot/stdout.expected + printf "RCPT TO:<${GOTD_DEVUSER}>\r\n" >> $testroot/stdout.expected + printf "DATA\r\n" >> $testroot/stdout.expected + printf "From: ${GOTD_USER}@${HOSTNAME}\r\n" >> $testroot/stdout.expected + printf "To: ${GOTD_DEVUSER}\r\n" >> $testroot/stdout.expected + printf "Subject: $GOTD_TEST_REPO_NAME: " >> $testroot/stdout.expected + printf "${GOTD_DEVUSER} changed refs/heads/main: $short_commit_id\r\n" \ + >> $testroot/stdout.expected + printf "\r\n" >> $testroot/stdout.expected + printf "commit $commit_id\n" >> $testroot/stdout.expected + printf "from: $GOT_AUTHOR\n" >> $testroot/stdout.expected + d=`date -u -r $author_time +"%a %b %e %X %Y UTC"` + printf "date: $d\n" >> $testroot/stdout.expected + printf "messagelen: 14\n" >> $testroot/stdout.expected + printf " \n" >> $testroot/stdout.expected + printf " make changes\n \n" >> $testroot/stdout.expected + printf " M alpha | 1+ 0-\n\n" >> $testroot/stdout.expected + printf "1 file changed, 1 insertion(+), 0 deletions(-)\n\n" \ + >> $testroot/stdout.expected + printf "\r\n" >> $testroot/stdout.expected + printf ".\r\n" >> $testroot/stdout.expected + printf "QUIT\r\n" >> $testroot/stdout.expected + + grep -v ^Date $testroot/stdout > $testroot/stdout.filtered + cmp -s $testroot/stdout.expected $testroot/stdout.filtered + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout.filtered + test_done "$testroot" "$ret" + return 1 + fi + + test_done "$testroot" "$ret" +} + test_parseargs "$@" run_test test_file_changed run_test test_many_commits_not_summarized @@ -640,3 +748,4 @@ run_test test_branch_removed run_test test_tag_created run_test test_tag_changed run_test test_file_empty +run_test test_tag_and_commit_created blob - /dev/null blob + e21f18c0ac2c63f52e3a11dcdb425253fa4fc022 (mode 755) --- /dev/null +++ regress/gotd/smtp-server @@ -0,0 +1,81 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2025 Stefan Sperling +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +require Net::Daemon; + +package GOTDSMTPServer; +our @ISA = qw(Net::Daemon); + +our $rounds = 1; + +sub Run ($) { + my ($self) = @_; + my ($line, $sock, $rc); + my @smtp_codes = (220, 250, 250, 250, 354, 250, 221); + + $sock = $self->{'socket'}; + foreach (@smtp_codes) { + $rc = printf $sock "$_\r\n"; + if (!$rc) { + $self->Error("Client connection error %s", + $sock->error()); + $sock->close(); + kill(SIGTERM, $$); + return; + } + if (!defined($line = $sock->getline())) { + if ($sock->error()) { + $self->Error("Client connection error %s", + $sock->error()); + } + $sock->close(); + kill(SIGTERM, $$); + return; + } + print $line; + } + + while (1) { + if (!defined($line = $sock->getline())) { + if ($sock->error()) { + $self->Error("Client connection error %s", + $sock->error()); + } + $sock->close(); + $rounds -= 1; + if ($rounds > 0) { + return; + } else { + kill(SIGTERM, $$); + } + } + print $line; + } +} + +package main; + +use Getopt::Long qw(:config bundling); + +my $port = 2525; + +GetOptions("p:i" => \$port, "r:i" => \$rounds) or die("usage: $0 [-p port] [-r rounds]\n"); + +my $server = GOTDSMTPServer->new({'pidfile' => 'none', 'mode' => 'single', \ + 'localaddr' => 127.0.0.1, 'localport' => 2525}, \@ARGV); + +STDOUT->autoflush(1); + +$server->Bind();