Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
v 2019.2
Changes in this release:
- various bugfixes (#1046, #968)
- various bugfixes (#1046, #968, #1045)
- Migration from mongodb to postgres
- added metering using pyformance
- added influxdb reporter for protocol endpoint metrics
Expand Down
6 changes: 1 addition & 5 deletions src/inmanta/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,7 @@ def export(options):
version, _ = export.run(types, scopes, metadata=metadata, model_export=options.model_export)

if exp is not None:
if not options.errors:
print(exp, file=sys.stderr)
sys.exit(1)
else:
raise exp
raise exp

if options.model:
modelexporter = ModelExporter(types)
Expand Down
2 changes: 1 addition & 1 deletion src/inmanta/ast/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def validate(cls, value):
return True

if not isinstance(value, numbers.Number):
raise RuntimeException(None, "Invalid value '%s'expected Number" % value)
raise RuntimeException(None, "Invalid value '%s', expected Number" % value)

return True # allow this function to be called from a lambda function

Expand Down
12 changes: 7 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,11 @@ def keep(self):
return {"env": self.env, "libs": self.libs, "project": self.project_dir}

def setup_for_snippet(self, snippet, autostd=True):
self.setup_for_snippet_external(snippet)

Project.set(Project(self.project_dir, autostd=autostd))

def setup_for_snippet_external(self, snippet):
with open(os.path.join(self.project_dir, "project.yml"), "w") as cfg:
cfg.write(
"""
Expand All @@ -506,15 +511,12 @@ def setup_for_snippet(self, snippet, autostd=True):
version: 1.0
repo: ['https://github.com/inmanta/']"""
% (self.libs,
os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", "modules"),
self.libs))

os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", "modules"),
self.libs))
self.main = os.path.join(self.project_dir, "main.cf")
with open(self.main, "w") as x:
x.write(snippet)

Project.set(Project(self.project_dir, autostd=autostd))

def do_export(self, include_status=False, do_raise=True):
return self._do_export(deploy=False, include_status=include_status, do_raise=do_raise)

Expand Down
244 changes: 198 additions & 46 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
from subprocess import TimeoutExpired


def get_command(tmp_dir, stdout_log_level=None, log_file=None, log_level_log_file=None, timed=False):
def get_command(
tmp_dir, stdout_log_level=None, log_file=None, log_level_log_file=None, timed=False
):
root_dir = tmp_dir.mkdir("root").strpath
log_dir = os.path.join(root_dir, "log")
state_dir = os.path.join(root_dir, "data")
Expand All @@ -38,7 +40,7 @@ def get_command(tmp_dir, stdout_log_level=None, log_file=None, log_level_log_fil

port = conftest.get_free_tcp_port()

with open(config_file, 'w+') as f:
with open(config_file, "w+") as f:
f.write("[config]\n")
f.write("log-dir=" + log_dir + "\n")
f.write("state-dir=" + state_dir + "\n")
Expand All @@ -59,10 +61,12 @@ def get_command(tmp_dir, stdout_log_level=None, log_file=None, log_level_log_fil
return (args, log_dir)


def do_run(args, env={}):
def do_run(args, env={}, cwd=None):
baseenv = os.environ.copy()
baseenv.update(env)
process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=baseenv)
process = subprocess.Popen(
args, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=baseenv
)
return process


Expand All @@ -71,8 +75,15 @@ def convert_to_ascii(text):


def do_kill(process, killtime=3, termtime=2):
t1 = Timer(killtime, process.kill)
t2 = Timer(termtime, process.terminate)
def do_and_log(func, msg):
def w():
print(msg)
func()

return w

t1 = Timer(killtime, do_and_log(process.kill, "killed process"))
t2 = Timer(termtime, do_and_log(process.terminate, "terminated process"))
t1.start()
t2.start()

Expand Down Expand Up @@ -100,14 +111,14 @@ def run_with_tty(args):


def get_timestamp_regex():
return r'[\d]{4}\-[\d]{2}\-[\d]{2} [\d]{2}\:[\d]{2}\:[\d]{2}\,[\d]{3}'
return r"[\d]{4}\-[\d]{2}\-[\d]{2} [\d]{2}\:[\d]{2}\:[\d]{2}\,[\d]{3}"


def get_compiled_regexes(regexes, timed):
result = []
for regex in regexes:
if timed:
regex = get_timestamp_regex() + ' ' + regex
regex = get_timestamp_regex() + " " + regex
compiled_regex = re.compile(regex)
result.append(compiled_regex)
return result
Expand All @@ -129,26 +140,91 @@ def test_verify_that_colorama_package_is_not_present():
assert not is_colorama_package_available()


@pytest.mark.parametrize("log_level, timed, with_tty, regexes_required_lines, regexes_forbidden_lines", [
(3, False, False, [r'[a-z.]*[ ]*INFO[\s]+Starting server endpoint',
r'[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint'], []),
(2, False, False, [r'[a-z.]*[ ]*INFO[\s]+Starting server endpoint'],
[r'[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint']),
(3, False, True, [r'\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint',
r'\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint'], []),
(2, False, True, [r'\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint'],
[r'\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint']),
(3, True, False, [r'[a-z.]*[ ]*INFO[\s]+Starting server endpoint',
r'[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint'], []),
(2, True, False, [r'[a-z.]*[ ]*INFO[\s]+Starting server endpoint'],
[r'[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint']),
(3, True, True, [r'\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint',
r'\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint'], []),
(2, True, True, [r'\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint'],
[r'\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint'])
])
@pytest.mark.parametrize(
"log_level, timed, with_tty, regexes_required_lines, regexes_forbidden_lines",
[
(
3,
False,
False,
[
r"[a-z.]*[ ]*INFO[\s]+Starting server endpoint",
r"[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint",
],
[],
),
(
2,
False,
False,
[r"[a-z.]*[ ]*INFO[\s]+Starting server endpoint"],
[r"[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint"],
),
(
3,
False,
True,
[
r"\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint",
r"\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint",
],
[],
),
(
2,
False,
True,
[
r"\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint"
],
[
r"\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint"
],
),
(
3,
True,
False,
[
r"[a-z.]*[ ]*INFO[\s]+Starting server endpoint",
r"[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint",
],
[],
),
(
2,
True,
False,
[r"[a-z.]*[ ]*INFO[\s]+Starting server endpoint"],
[r"[a-z.]*[ ]*DEBUG[\s]+Starting Server Rest Endpoint"],
),
(
3,
True,
True,
[
r"\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint",
r"\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint",
],
[],
),
(
2,
True,
True,
[
r"\x1b\[32m[a-z.]*[ ]*INFO[\s]*\x1b\[0m \x1b\[34mStarting server endpoint"
],
[
r"\x1b\[36m[a-z.]*[ ]*DEBUG[\s]*\x1b\[0m \x1b\[34mStarting Server Rest Endpoint"
],
),
],
)
@pytest.mark.timeout(20)
def test_no_log_file_set(tmpdir, log_level, timed, with_tty, regexes_required_lines, regexes_forbidden_lines):
def test_no_log_file_set(
tmpdir, log_level, timed, with_tty, regexes_required_lines, regexes_forbidden_lines
):
if is_colorama_package_available() and with_tty:
pytest.skip("Colorama is present")

Expand All @@ -163,51 +239,91 @@ def test_no_log_file_set(tmpdir, log_level, timed, with_tty, regexes_required_li
check_logs(stdout, regexes_required_lines, regexes_forbidden_lines, timed)


@pytest.mark.parametrize("log_level, with_tty, regexes_required_lines, regexes_forbidden_lines", [
(3, False, [r'[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint',
r'[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint'], []),
(2, False, [r'[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint'],
[r'[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint']),
(3, True, [r'[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint',
r'[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint'], []),
(2, True, [r'[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint'],
[r'[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint'])
])
@pytest.mark.parametrize(
"log_level, with_tty, regexes_required_lines, regexes_forbidden_lines",
[
(
3,
False,
[
r"[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint",
r"[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint",
],
[],
),
(
2,
False,
[r"[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint"],
[r"[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint"],
),
(
3,
True,
[
r"[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint",
r"[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint",
],
[],
),
(
2,
True,
[r"[a-z.]*[ ]*INFO[\s]+[a-x\.A-Z]*[\s]Starting server endpoint"],
[r"[a-z.]*[ ]*DEBUG[\s]+[a-x\.A-Z]*[\s]Starting Server Rest Endpoint"],
),
],
)
@pytest.mark.timeout(60)
def test_log_file_set(tmpdir, log_level, with_tty, regexes_required_lines, regexes_forbidden_lines):
def test_log_file_set(
tmpdir, log_level, with_tty, regexes_required_lines, regexes_forbidden_lines
):
if is_colorama_package_available() and with_tty:
pytest.skip("Colorama is present")

log_file = "server.log"
(args, log_dir) = get_command(tmpdir, stdout_log_level=log_level, log_file=log_file, log_level_log_file=log_level)
(args, log_dir) = get_command(
tmpdir,
stdout_log_level=log_level,
log_file=log_file,
log_level_log_file=log_level,
)
if with_tty:
(stdout, _) = run_with_tty(args)
else:
(stdout, _) = run_without_tty(args)
assert log_file in os.listdir(log_dir)
log_file = os.path.join(log_dir, log_file)
with open(log_file, 'r') as f:
with open(log_file, "r") as f:
log_lines = f.readlines()
check_logs(log_lines, regexes_required_lines, regexes_forbidden_lines, timed=True)
check_logs(stdout, [], regexes_required_lines, timed=True)
check_logs(stdout, [], regexes_required_lines, timed=False)


def check_logs(log_lines, regexes_required_lines, regexes_forbidden_lines, timed):
compiled_regexes_requires_lines = get_compiled_regexes(regexes_required_lines, timed)
compiled_regexes_forbidden_lines = get_compiled_regexes(regexes_forbidden_lines, timed)
compiled_regexes_requires_lines = get_compiled_regexes(
regexes_required_lines, timed
)
compiled_regexes_forbidden_lines = get_compiled_regexes(
regexes_forbidden_lines, timed
)
for line in log_lines:
print(line)
for regex in compiled_regexes_requires_lines:
if not any(regex.match(line) for line in log_lines):
pytest.fail("Required pattern was not found in log lines: %s" % (regex.pattern,))
pytest.fail(
"Required pattern was not found in log lines: %s" % (regex.pattern,)
)
for regex in compiled_regexes_forbidden_lines:
if any(regex.match(line) for line in log_lines):
pytest.fail("Forbidden pattern found in log lines: %s" % (regex.pattern,))


def test_check_shutdown():
process = do_run([sys.executable, os.path.join(os.path.dirname(__file__), "miniapp.py")])
process = do_run(
[sys.executable, os.path.join(os.path.dirname(__file__), "miniapp.py")]
)
# wait for handler to be in place
try:
process.communicate(timeout=2)
Expand All @@ -222,10 +338,46 @@ def test_check_shutdown():


def test_check_bad_shutdown():
print([sys.executable, os.path.join(os.path.dirname(__file__), "miniapp.py"), "bad"])
process = do_run([sys.executable, os.path.join(os.path.dirname(__file__), "miniapp.py"), "bad"])
print(
[sys.executable, os.path.join(os.path.dirname(__file__), "miniapp.py"), "bad"]
)
process = do_run(
[sys.executable, os.path.join(os.path.dirname(__file__), "miniapp.py"), "bad"]
)
out, err = do_kill(process, killtime=5, termtime=2)
print(out, err)
assert "----- Thread Dump ----" in out
assert "STOP" not in out
assert "SHUTDOWN COMPLETE" not in out


def test_compiler_exception_output(snippetcompiler):
snippetcompiler.setup_for_snippet_external(
"""
entity Test:
number attr
end

implement Test using std::none

o = Test(attr="1234")
"""
)

output = """Could not set attribute `attr` on instance `__config__::Test (instantiated at ./main.cf:8)` """ \
"""(reported in Construct(Test) (./main.cf:8))
caused by:
Invalid value '1234', expected Number (reported in Construct(Test) (./main.cf:8))
"""

def exec(*cmd):
process = do_run(
[sys.executable, "-m", "inmanta.app"] + list(cmd),
cwd=snippetcompiler.project_dir,
)
out, err = process.communicate(timeout=5)
assert out.decode() == ""
assert err.decode() == output
Comment thread
arnaudsjs marked this conversation as resolved.

exec("compile")
exec("export", "-J", "out.json")