Initial commit: one_os_compositor Odoo 20 addon — core OWL library + backend models + JWT auth
Includes:
- compositor.app, compositor.session, compositor.session.app, compositor.audit.log models
- /web/compositor/{token,apps,launch,audit} HTTP controllers with JWT (HS256)
- CompositorService OWL service (reusable via useService('compositor'))
- CompositorCanvas OWL component (reusable canvas wrapper)
- Security: compositor_group_user, compositor_group_manager groups + ir.access.csv rules
- 5 demo apps pre-loaded (gnome-calculator, xterm, gtk4-demo, glxgears, featherpad)
- Audit log capturing JWT issuance + app launch events
- Stub mode: launching apps returns a stub SurfaceHandle when proxy isn't connected
- Tested against Odoo 20 + PostgreSQL 17
Author: 1bspace.com
Parent company: 1B Global
License: Proprietary (1B Space internal use)
This commit is contained in:
commit
93a5a0a221
32 files changed
+2497
No files matched your search
@@ -0,0 +1,69 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Tests for compositor HTTP controllers."""
|
||||
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestCompositorController(HttpCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Make sure a JWT secret is set
|
||||
self.env["ir.config_parameter"].set_str(
|
||||
"compositor.jwt_secret", "test-secret-1bspace"
|
||||
)
|
||||
|
||||
def test_get_token(self):
|
||||
"""Test that /web/compositor/token returns a valid JWT."""
|
||||
self.authenticate("admin", "admin")
|
||||
response = self.url_open(
|
||||
"/web/compositor/token",
|
||||
data="{}",
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200, response.text)
|
||||
result = response.json()
|
||||
self.assertIn("jwt", result["result"])
|
||||
self.assertIn("proxy_url", result["result"])
|
||||
self.assertIn("expires_at", result["result"])
|
||||
self.assertIn("compositor_session_id", result["result"])
|
||||
|
||||
def test_list_apps(self):
|
||||
"""Test that /web/compositor/apps returns the pre-installed apps."""
|
||||
self.authenticate("admin", "admin")
|
||||
response = self.url_open(
|
||||
"/web/compositor/apps",
|
||||
data="{}",
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200, response.text)
|
||||
result = response.json()["result"]
|
||||
self.assertIn("apps", result)
|
||||
app_ids = [a["app_id"] for a in result["apps"]]
|
||||
self.assertIn("gnome-calculator", app_ids)
|
||||
self.assertIn("xterm", app_ids)
|
||||
|
||||
def test_launch_app_stub(self):
|
||||
"""Test that launching an app returns a stub response when proxy isn't connected."""
|
||||
self.authenticate("admin", "admin")
|
||||
# First get a token
|
||||
token_resp = self.url_open(
|
||||
"/web/compositor/token",
|
||||
data="{}",
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30,
|
||||
).json()["result"]
|
||||
# Then try to launch
|
||||
response = self.url_open(
|
||||
"/web/compositor/launch",
|
||||
data='{"app_id": "gnome-calculator"}',
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200, response.text)
|
||||
result = response.json()["result"]
|
||||
# Since proxy isn't connected, we should get a stub
|
||||
self.assertTrue(result.get("stub", False))
|
||||
self.assertIn("compositor_surface_id", result)
|
||||
Reference in new issue
Block a user