Add script for testing Snikket launch end-to-end

Amolith created

Change summary

bin/test_snikket_launch | 137 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)

Detailed changes

bin/test_snikket_launch 🔗

@@ -0,0 +1,137 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require "dhall"
+require "net/http"
+require "uri"
+require "time"
+require "em-http"
+require "em-synchrony/em-http"
+require "link-header-parser"
+
+require_relative "../lib/em"
+require_relative "../lib/blather_notify"
+require_relative "../lib/form_to_h"
+require "ougai"
+
+$stdout.sync = true
+LOG = Ougai::Logger.new($stdout)
+LOG.level = ENV.fetch("LOG_LEVEL", "info")
+LOG.formatter = Ougai::Formatters::Readable.new(
+	nil,
+	nil,
+	plain: !$stdout.isatty
+)
+Blather.logger = LOG
+
+CONFIG = Dhall.load(<<-DHALL).sync
+	(#{ARGV[0]}) : {
+		node: Text,
+		jid: Text,
+		password: Text,
+		sgx_jmp: Text,
+		interval: Int,
+		max_attempts: Int
+	}
+DHALL
+
+DOMAIN = "jmp-test-#{Time.now.to_i}.snikket.chat"
+
+using FormToH
+
+class TestInstance
+	def launch
+		puts "Launching instance at #{DOMAIN}"
+		BlatherNotify.execute(
+			"snikket",
+			{ domain: DOMAIN }.to_form(:submit)
+		).then do |iq|
+			@id = iq.form.field("instance-id").value.to_s
+			@uri = iq.form.field("bootstrap-uri").value.to_s
+		end
+	end
+
+	def extract_link(res)
+		LinkHeaderParser.parse(
+			Array(res.response_header["LINK"].sub(/>([^:])/, ">;\\1")), base: @uri
+		).group_by_relation_type[:alternate].find { |header|
+			URI.parse(header.target_uri).scheme == "xmpp"
+		}.target_uri
+	end
+
+	def ping_http(attempt: 0)
+		raise "Couldn't ping #{DOMAIN} over HTTP" if attempt > CONFIG[:max_attempts]
+
+		EM::HttpRequest.new(
+			@uri, tls: { verify_peer: true }
+		).ahead(redirects: 5).then { |res| extract_link(res) }.catch { |e|
+			puts "HTTP ping attempt #{attempt} failed: #{e}"
+			EM.promise_timer(CONFIG[:interval]).then {
+				ping_http(attempt: attempt + 1)
+			}
+		}
+	end
+
+	def ping_xmpp(attempt: 0)
+		raise "Couldn't ping {#DOMAIN} over XMPP" if attempt > CONFIG[:max_attempts]
+
+		BlatherNotify.write_with_promise(
+			Blather::Stanza::Iq::Ping.new(:get, DOMAIN)
+		).catch { |e|
+			puts "XMPP ping attempt #{attempt} failed: #{e}"
+			EM.promise_timer(CONFIG[:interval]).then {
+				ping_xmpp(attempt: attempt + 1)
+			}
+		}
+	end
+
+	def stop
+		puts "Stopping instance at #{DOMAIN}"
+		BlatherNotify.execute(
+			"stop snikket",
+			{ instance_id: @id }.to_form(:submit)
+		).then do |iq|
+			raise "Couldn't stop instance: #{iq.note}" if iq.note_type == :error
+		end
+	end
+
+	def delete
+		puts "Deleting instance at #{DOMAIN}"
+		BlatherNotify.execute(
+			"delete snikket",
+			{ instance_id: @id }.to_form(:submit)
+		).then do |iq|
+			puts iq
+			raise "Couldn't stop instance: #{iq.note}" if iq.note_type == :error
+		end
+	end
+end
+
+EM.run do
+	instance = TestInstance.new
+
+	BlatherNotify.start(
+		CONFIG[:jid],
+		CONFIG[:password]
+	).then {
+		instance.launch
+	}.then {
+		puts "Launch instance success"
+		instance.ping_http
+	}.then {
+		puts "HTTP ping success"
+		instance.ping_xmpp
+	}.then {
+		puts "XMPP ping success"
+		instance.stop
+	}.then {
+		puts "Stop instance success"
+		instance.delete
+	}.catch { |e|
+		p e
+		exit 1
+	}.then {
+		puts "Delete instance success"
+		EM.stop
+	}
+end