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