Skip to content

Commit d5f4e5a

Browse files
demo-e2e-testing
Summary: - Support for E2E testing of demo materials.
1 parent 4eee90e commit d5f4e5a

File tree

4 files changed

+112
-2
lines changed

4 files changed

+112
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ y.output
3030
*.pyc
3131

3232
.stackql/
33+
34+
.venv/

cicd/env/.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
pyenv/
2-
*.sh
1+
*
2+
!.gitignore

cicd/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ PyYaml>=6.0.1
55
requests==2.32.3
66
robotframework==6.1.1
77
sqlalchemy==1.4.44
8+
9+
mistune==3.0.2
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import mistune
2+
3+
from typing import List, Tuple
4+
5+
import subprocess, os, sys
6+
7+
class ASTNode(object):
8+
9+
def __init__(self, node: dict):
10+
self.node = node
11+
self.children = []
12+
if 'children' in node:
13+
for child in node['children']:
14+
self.children.append(ASTNode(child))
15+
16+
def get_type(self) -> str:
17+
return self.node.get('type', '')
18+
19+
def get_text(self) -> str:
20+
return self.node.get('text', '')
21+
22+
def is_executable(self) -> bool:
23+
return self.get_type() == 'code_block'
24+
25+
def get_execution_language(self) -> str:
26+
return self.node.get('lang', '')
27+
28+
29+
class MdParser(object):
30+
31+
def parse_markdown_file(self, file_path: str, lang=None) -> List[ASTNode]:
32+
markdown: mistune.Markdown = mistune.create_markdown(renderer='ast')
33+
with open(file_path, 'r') as f:
34+
txt = f.read()
35+
return markdown(txt)
36+
37+
38+
class MdExecutor(object):
39+
40+
def __init__(self, renderer: MdParser):
41+
self.renderer = renderer
42+
43+
def execute(self, file_path: str) -> None:
44+
ast = self.renderer.parse_markdown_file(file_path)
45+
for node in ast:
46+
if node.is_executable():
47+
lang = node.get_execution_language()
48+
if lang == 'python':
49+
exec(node.get_text())
50+
else:
51+
print(f'Unsupported language: {lang}')
52+
53+
class WorkloadDTO(object):
54+
55+
def __init__(self, setup: str, in_session: List[str], teardown: str):
56+
self._setup = setup
57+
self._in_session = in_session
58+
self._teardown = teardown
59+
60+
def get_setup(self) -> List[str]:
61+
return self._setup
62+
63+
def get_in_session(self) -> List[str]:
64+
return self._in_session
65+
66+
def get_teardown(self) -> List[str]:
67+
return self._teardown
68+
69+
class SimpleE2E(object):
70+
71+
def __init__(self, workload: WorkloadDTO):
72+
self._workload = workload
73+
74+
def run(self) -> Tuple[bytes, bytes]:
75+
pr: subprocess.Popen = subprocess.Popen(
76+
self._workload.get_setup(),
77+
stdin=subprocess.PIPE,
78+
stdout=subprocess.PIPE,
79+
stderr=subprocess.PIPE,
80+
shell=True,
81+
executable='/bin/bash'
82+
)
83+
for cmd in self._workload.get_in_session():
84+
pr.stdin.write(f"{cmd}\n".encode(sys.getdefaultencoding()))
85+
pr.stdin.flush()
86+
stdoout_bytes, stderr_bytes = pr.communicate()
87+
return (stdoout_bytes, stderr_bytes,)
88+
89+
if __name__ == '__main__':
90+
workload_dto: WorkloadDTO = WorkloadDTO(
91+
setup="""
92+
export GOOGLE_CREDENTIALS="$(cat /Users/admin/stackql/secrets/concerted-testing/google-credentials.json)" &&
93+
stackql shell""",
94+
in_session=[
95+
'registry pull google;',
96+
'select name, id FROM google.compute.instances WHERE project = \'ryuki-it-sandbox-01\' AND zone = \'australia-southeast1-a\';'
97+
],
98+
teardown='echo "Goodbye, World!"'
99+
)
100+
e2e: SimpleE2E = SimpleE2E(workload_dto)
101+
stdout_bytes, stderr_bytes = e2e.run()
102+
print(stdout_bytes.decode(sys.getdefaultencoding()))
103+
print(stderr_bytes.decode(sys.getdefaultencoding()))
104+
105+
106+

0 commit comments

Comments
 (0)