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
25 changes: 17 additions & 8 deletions tests/system/framework/hosts/shadow.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,21 +398,27 @@ def __setitem__(self, key: str, value: str) -> None:
self.logger.info(f"Setting {key}={value} in {self.path} on {self.host.hostname}")

sep = self.separator
grep_match = "=" if sep == "=" else "\\s"
awk_match = "=" if sep == "=" else "\\\\s"
if sep == "=":
grep_pattern = f"^{key}="
grep_comment_pattern = f"^# *{key}="
awk_pattern = "="
else:
grep_pattern = f"^{key}\\s+"
grep_comment_pattern = f"^# *{key}\\s+"
awk_pattern = "[[:space:]]+"

# Escape special characters for awk
escaped_value = value.replace("/", "\\/")

self.host.conn.run(
f"""
if grep -q '^{key}{grep_match}' {self.path}; then
if grep -qE '{grep_pattern}' {self.path}; then
awk -v key="{key}" -v val="{escaped_value}" \\
'{{if ($0 ~ "^" key "{awk_match}") print key "{sep}" val; else print $0}}' \\
'{{if ($0 ~ "^" key "{awk_pattern}") print key "{sep}" val; else print $0}}' \\
{self.path} > {self.path}.tmp && mv {self.path}.tmp {self.path}
elif grep -q '^#\\s*{key}{grep_match}' {self.path}; then
elif grep -qE '{grep_comment_pattern}' {self.path}; then
awk -v key="{key}" -v val="{escaped_value}" \\
'{{if ($0 ~ "^#\\\\s*" key "{awk_match}") print key "{sep}" val; else print $0}}' \\
'{{if ($0 ~ "^# *" key "{awk_pattern}") print key "{sep}" val; else print $0}}' \\
{self.path} > {self.path}.tmp && mv {self.path}.tmp {self.path}
else
echo '{key}{sep}{value}' >> {self.path}
Expand All @@ -432,5 +438,8 @@ def __delitem__(self, key: str) -> None:
self._ensure_exists()
self.logger.info(f"Removing {key} from {self.path} on {self.host.hostname}")

match = "=" if self.separator == "=" else "\\s"
self.host.conn.run(f"sed -i 's/^{key}{match}.*/#&/' {self.path}", log_level=ProcessLogLevel.Error)
if self.separator == "=":
pattern = f"^{key}="
else:
pattern = f"^{key}\\s+"
self.host.conn.run(f"sed -iE 's/{pattern}.*/#&/' {self.path}", log_level=ProcessLogLevel.Error)
89 changes: 89 additions & 0 deletions tests/system/tests/test_groupadd.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,3 +512,92 @@ def test_groupadd__invalid_arguments(shadow: Shadow, args: str):
shadow.groupadd(args)

assert exc_info.value.rc == 2, f"Expected return code 2(invalid usage), got {exc_info.value.rc}"


@pytest.mark.topology(KnownTopology.Shadow)
def test_groupadd__no_gshadow(shadow: Shadow):
"""
:title: Group creation succeeds when /etc/gshadow does not exist
:setup:
1. Remove /etc/gshadow file
2. Set FORCE_SHADOW=no in /etc/login.defs
:steps:
1. Create group
2. Check group entry
3. Check that /etc/gshadow file is not present
:expectedresults:
1. Group is created
2. Group entry is found
3. /etc/gshadow file is not found
:customerscenario: False
"""
shadow.fs.rm("/etc/gshadow")

shadow.login_defs["FORCE_SHADOW"] = "no"
Comment thread
ikerexxe marked this conversation as resolved.

shadow.groupadd("tgroup")

group_entry = shadow.tools.getent.group("tgroup")
assert group_entry is not None, "Group should be found"
assert group_entry.name == "tgroup", "Incorrect groupname"

gshadow_file = shadow.fs.exists("/etc/gshadow")
assert not gshadow_file, "/etc/gshadow file should not be found"


@pytest.mark.topology(KnownTopology.Shadow)
def test_groupadd__non_unique_requires_gid(shadow: Shadow):
"""
:title: Groupadd command fails when non-unique option is used without GID
:setup:
1. None required
:steps:
1. Attempt to create group
2. Verify that groupadd command fails
3. Check group and gshadow entries
:expectedresults:
1. Group is not created
2. groupadd command fails with error (invalid usage)
3. No group or gshadow entries are found
:customerscenario: False
"""
with pytest.raises(ProcessError) as exc_info:
shadow.groupadd("-o tgroup")

assert exc_info.value.rc == 2, f"Expected return code 2 (invalid usage), got {exc_info.value.rc}"

group_entry = shadow.tools.getent.group("tgroup")
assert group_entry is None, "Group should not be found"

if shadow.host.features["gshadow"]:
gshadow_entry = shadow.tools.getent.gshadow("tgroup")
assert gshadow_entry is None, "Group should not be found"


@pytest.mark.topology(KnownTopology.Shadow)
def test_groupadd__invalid_option(shadow: Shadow):
"""
:title: Group creation fails with invalid option
:setup:
1. None required
:steps:
1. Attempt to create group
2. Verify that groupadd command fails
3. Check group and gshadow entries
:expectedresults:
1. Group is not created
2. groupadd command fails with error (invalid usage)
3. No group or gshadow entries are found
:customerscenario: False
"""
with pytest.raises(ProcessError) as exc_info:
shadow.groupadd("-invalid tgroup")

assert exc_info.value.rc == 2, f"Expected return code 2 (invalid usage), got {exc_info.value.rc}"

group_entry = shadow.tools.getent.group("tgroup")
assert group_entry is None, "Group should not be found"

if shadow.host.features["gshadow"]:
gshadow_entry = shadow.tools.getent.gshadow("tgroup")
assert gshadow_entry is None, "Group should not be found"
Loading