module HTTP_Adapter {

/* HTTP Adapter component, originally part of Integration Tests for osmo-remsim-server
 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * This test suite tests osmo-remsim-server by attaching to the external interfaces
 * such as RSPRO for simulated clients + bankds and RSRES (REST backend interface).
 */

import from HTTPmsg_Types all;
import from HTTPmsg_PortType all;

type component http_CT {
	port HTTPmsg_PT HTTP;
	var charstring g_http_host;
	var integer g_http_port;
};

function f_http_init(charstring host, integer http_port) runs on http_CT {
	map(self:HTTP, system:HTTP);
	g_http_host := host;
	g_http_port := http_port;
}

template (value) Connect ts_HTTP_Connect(template (value) charstring hostname,
					 template (value) integer http_port := 80,
					 template (value) boolean use_ssl := false) := {
	hostname := hostname,
	portnumber := http_port,
	use_ssl := use_ssl
}
template (value) Close ts_HTTP_Close := { client_id := omit };

template (value) HeaderLines ts_HTTP_Header(charstring body) := {
	{ header_name := "Content-Type", header_value := "application/json" },
	{ header_name := "Content-Length", header_value := int2str(lengthof(body)) }
}

template (value) HTTPMessage ts_HTTP_Req(charstring url,
					 charstring method := "GET",
					 charstring body := "",
					 integer v_maj := 1, integer v_min := 1) := {
	request := {
		client_id := omit,
		method := method,
		uri := url,
		version_major := v_maj,
		version_minor := v_min,
		header := ts_HTTP_Header(body),
		body := body
	}
}

template HTTPMessage tr_HTTP_Resp(template integer sts := ?) := {
	response := {
		client_id := ?,
		version_major := ?,
		version_minor := ?,
		statuscode := sts,
		statustext := ?,
		header := ?,
		body := ?
	}
};

template HTTPMessage tr_HTTP_Resp2xx := tr_HTTP_Resp((200..299));

function f_http_tx_request(charstring url, charstring method := "GET", charstring body := "")
runs on http_CT {
	HTTP.send(ts_HTTP_Connect(g_http_host, g_http_port));
	HTTP.receive(Connect_result:?);
	HTTP.send(ts_HTTP_Req(url, method, body));
}

function f_http_rx_response(template HTTPMessage exp := tr_HTTP_Resp2xx, float tout := 2.0)
runs on http_CT return HTTPMessage {
	var HTTPMessage resp;
	timer T := tout;
	T.start;
	alt {
	[] HTTP.receive(exp) -> value resp {
		setverdict(pass);
		}
	[] HTTP.receive(tr_HTTP_Resp) -> value resp {
		setverdict(fail, "Unexpected HTTP response ", resp);
		}
	[] T.timeout {
		setverdict(fail, "Timeout waiting for HTTP response");
		self.stop;
		}
	}
	HTTP.send(ts_HTTP_Close);
	return resp;
}

/* run a HTTP request and return the response */
function f_http_transact(charstring url, charstring method := "GET",
			 charstring body := "", template HTTPMessage exp := tr_HTTP_Resp2xx,
			 float tout := 2.0)
runs on http_CT return HTTPMessage {
	f_http_tx_request(url, method, body);
	return f_http_rx_response(exp, tout);
}

}
