2019-05-30 00:14:26 +00:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
|
|
|
import composertest
|
|
|
|
import requests
|
|
|
|
import subprocess
|
2019-07-05 14:21:27 +00:00
|
|
|
import json
|
2019-05-30 00:14:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TestApi(composertest.ComposerTestCase):
|
|
|
|
"""Test Composer HTTP API"""
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
|
|
|
|
# Forward /run/weldr/api.socket to a port on the host
|
|
|
|
# Set ExitOnForwardFailure so that ssh blocks until the forward is set
|
|
|
|
# up before going to the background (-f), which it closes stdout. We
|
|
|
|
# wait for that by calling read() on it.
|
|
|
|
self.composer_port = self.network._lock(8080)
|
|
|
|
forwarder_command = [*self.ssh_command, "-fNT",
|
|
|
|
"-o", "ExitOnForwardFailure=yes",
|
|
|
|
"-L", f"localhost:{self.composer_port}:/run/weldr/api.socket"]
|
|
|
|
self.forwarder_proc = subprocess.Popen(forwarder_command, stdout=subprocess.PIPE)
|
|
|
|
self.forwarder_proc.stdout.read()
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
self.forwarder_proc.terminate()
|
|
|
|
try:
|
|
|
|
self.forwarder_proc.wait(timeout=1)
|
|
|
|
except TimeoutError:
|
|
|
|
self.forwarder_proc.kill()
|
|
|
|
super().tearDown()
|
|
|
|
|
2019-07-05 14:21:27 +00:00
|
|
|
def request(self, method, path, json=None, check=True):
|
2019-05-30 00:14:26 +00:00
|
|
|
self.assertEqual(path[0], "/")
|
2019-07-05 14:21:27 +00:00
|
|
|
r = requests.request(method, f"http://localhost:{self.composer_port}{path}", json=json, timeout=30)
|
2019-05-30 00:14:26 +00:00
|
|
|
if check:
|
|
|
|
r.raise_for_status()
|
|
|
|
return r
|
|
|
|
|
|
|
|
def test_basic(self):
|
|
|
|
"""Basic checks for the API"""
|
|
|
|
|
|
|
|
#
|
|
|
|
# API status without depsolve errors
|
|
|
|
#
|
2019-05-31 16:35:01 +00:00
|
|
|
r = self.request("GET", "/api/status")
|
|
|
|
self.assertEqual(r.status_code, 200)
|
|
|
|
status = r.json()
|
2019-05-30 00:14:26 +00:00
|
|
|
self.assertEqual(status.keys(), { "build", "api", "db_version", "schema_version", "db_supported", "backend", "msgs" })
|
|
|
|
self.assertEqual(status["msgs"], [])
|
2019-05-31 16:35:01 +00:00
|
|
|
self.assertEqual(r.headers.keys(), { "Content-Type", "Content-Length", "Date" })
|
2019-05-30 00:14:26 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# HTTP errors should return json responses
|
|
|
|
#
|
|
|
|
r = self.request("GET", "/marmalade", check=False)
|
|
|
|
self.assertEqual(r.status_code, 404)
|
|
|
|
self.assertEqual(r.json(), {
|
|
|
|
"status": False,
|
|
|
|
"errors": [{ "id": "HTTPError", "code": 404, "msg": "Not Found" }]
|
|
|
|
})
|
|
|
|
|
|
|
|
r = self.request("POST", "/api/status", check=False)
|
|
|
|
self.assertEqual(r.status_code, 405)
|
|
|
|
self.assertEqual(r.json(), {
|
|
|
|
"status": False,
|
|
|
|
"errors": [{ "id": "HTTPError", "code": 405, "msg": "Method Not Allowed" }]
|
|
|
|
})
|
|
|
|
|
2019-07-05 14:21:27 +00:00
|
|
|
#
|
|
|
|
# API create blueprint with InvalidChars
|
|
|
|
#
|
|
|
|
invalid_blueprint = {
|
|
|
|
"name": "Name,With,Commas",
|
|
|
|
"description": "",
|
|
|
|
"version": "0.0.1",
|
|
|
|
"modules": [],
|
|
|
|
"groups": []
|
|
|
|
}
|
|
|
|
|
|
|
|
r = self.request("POST", "/api/v0/blueprints/new", json=invalid_blueprint, check=False)
|
|
|
|
self.assertEqual(r.status_code, 400)
|
|
|
|
self.assertEqual(r.json(), {
|
|
|
|
"status": False,
|
|
|
|
"errors": [{ "id": "InvalidChars", "code": 400, "msg": "Invalid characters in API path" }]
|
|
|
|
})
|
|
|
|
|
2019-05-30 00:14:26 +00:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
composertest.main()
|