test_snikket_launch

  1#!/usr/bin/env ruby
  2# frozen_string_literal: true
  3
  4require "dhall"
  5require "net/http"
  6require "uri"
  7require "time"
  8require "em-http"
  9require "em-synchrony/em-http"
 10require "link-header-parser"
 11
 12require_relative "../lib/em"
 13require_relative "../lib/blather_notify"
 14require_relative "../lib/form_to_h"
 15require "ougai"
 16
 17$stdout.sync = true
 18LOG = Ougai::Logger.new($stdout)
 19LOG.level = ENV.fetch("LOG_LEVEL", "info")
 20LOG.formatter = Ougai::Formatters::Readable.new(
 21	nil,
 22	nil,
 23	plain: !$stdout.isatty
 24)
 25Blather.logger = LOG
 26
 27SCHEMA = "{
 28	jid: Text,
 29	password: Text,
 30	sgx_jmp: Text,
 31	interval: Natural,
 32	max_attempts: Natural
 33}"
 34
 35CONFIG = Dhall::Coder
 36	.new(safe: Dhall::Coder::JSON_LIKE)
 37	.load("#{ARGV.first} : #{SCHEMA}", transform_keys: :to_sym)
 38
 39DOMAIN = "jmp-test-#{Time.now.to_i}.snikket.chat"
 40
 41using FormToH
 42
 43class TestInstance
 44	def launch
 45		puts "Launching instance at #{DOMAIN}"
 46		BlatherNotify.execute(
 47			"snikket",
 48			{ domain: DOMAIN }.to_form(:submit)
 49		).then do |iq|
 50			@id = iq.form.field("instance-id").value.to_s
 51			@uri = iq.form.field("bootstrap-uri").value.to_s
 52		end
 53	end
 54
 55	def extract_link(res)
 56		LinkHeaderParser.parse(
 57			Array(res.response_header["LINK"]), base: @uri
 58		).group_by_relation_type[:alternate].find { |header|
 59			URI.parse(header.target_uri).scheme == "xmpp"
 60		}.target_uri
 61	end
 62
 63	def ping_http(attempt: 0)
 64		raise "Couldn't ping #{DOMAIN} over HTTP" if attempt > CONFIG[:max_attempts]
 65
 66		EM::HttpRequest.new(
 67			@uri, tls: { verify_peer: true }
 68		).ahead(redirects: 5).then { |res| extract_link(res) }.catch { |e|
 69			puts "HTTP ping attempt #{attempt} failed: #{e}"
 70			EM.promise_timer(CONFIG[:interval]).then {
 71				ping_http(attempt: attempt + 1)
 72			}
 73		}
 74	end
 75
 76	def ping_xmpp(attempt: 0)
 77		raise "Couldn't ping {#DOMAIN} over XMPP" if attempt > CONFIG[:max_attempts]
 78
 79		BlatherNotify.write_with_promise(
 80			Blather::Stanza::Iq::Ping.new(:get, DOMAIN)
 81		).catch { |e|
 82			puts "XMPP ping attempt #{attempt} failed: #{e}"
 83			EM.promise_timer(CONFIG[:interval]).then {
 84				ping_xmpp(attempt: attempt + 1)
 85			}
 86		}
 87	end
 88
 89	def stop
 90		puts "Stopping instance at #{DOMAIN}"
 91		BlatherNotify.execute(
 92			"stop snikket",
 93			{ instance_id: @id }.to_form(:submit)
 94		).then do |iq|
 95			raise "Couldn't stop instance: #{iq.note}" if iq.note_type == :error
 96		end
 97	end
 98
 99	def delete
100		puts "Deleting instance at #{DOMAIN}"
101		BlatherNotify.execute(
102			"delete snikket",
103			{ instance_id: @id }.to_form(:submit)
104		).then do |iq|
105			puts iq
106			raise "Couldn't stop instance: #{iq.note}" if iq.note_type == :error
107		end
108	end
109end
110
111EM.run do
112	instance = TestInstance.new
113
114	BlatherNotify.start(
115		CONFIG[:jid],
116		CONFIG[:password]
117	).then {
118		instance.launch
119	}.then {
120		puts "Launch instance success"
121		instance.ping_http
122	}.then {
123		puts "HTTP ping success"
124		instance.ping_xmpp
125	}.then {
126		puts "XMPP ping success"
127		instance.stop
128	}.then {
129		puts "Stop instance success"
130		instance.delete
131	}.catch { |e|
132		p e
133		exit(e == :timeout ? 0 : 1)
134	}.then {
135		puts "Delete instance success"
136		EM.stop
137	}
138end