Skip to content

Commit

Permalink
[antlir2][image_test] fix run_as_user
Browse files Browse the repository at this point in the history
Summary:
This is almost always `root`, so there was a bug where it actually just wasn't
respected.

Test Plan:
```
❯ buck test fbcode//antlir/antlir2/testing/tests:test-{cpp,py,rust,sh}{,-booted}{,-nobody}
❯ buck2 test fbcode//antlir/antlir2/testing/tests:test-cpp fbcode//antlir/antlir2/testing/tests:test-cpp-nobody fbcode//antlir/antlir2/testing/tests:test-cpp-booted fbcode//antlir/antlir2/testing/tests:test-cpp-booted-nobody fbcode//antlir/antlir2/testing/tests:test-py fbcode//antlir/antlir2/testing/tests:test-py-nobody fbcode//antlir/antlir2/testing/tests:test-py-booted fbcode//antlir/antlir2/testing/tests:test-py-booted-nobody fbcode//antlir/antlir2/testing/tests:test-rust fbcode//antlir/antlir2/testing/tests:test-rust-nobody fbcode//antlir/antlir2/testing/tests:test-rust-booted fbcode//antlir/antlir2/testing/tests:test-rust-booted-nobody fbcode//antlir/antlir2/testing/tests:test-sh fbcode//antlir/antlir2/testing/tests:test-sh-nobody fbcode//antlir/antlir2/testing/tests:test-sh-booted fbcode//antlir/antlir2/testing/tests:test-sh-booted-nobody
Buck UI: https://www.internalfb.com/buck2/61a6eeed-c724-47f3-a9e1-2c5477755d58
Test UI: https://www.internalfb.com/intern/testinfra/testrun/6192449637559960
Network: Up: 168KiB  Down: 114KiB  (reSessionID-bf4f1f71-3662-4499-93eb-cd6bf1473fac)
Jobs completed: 278. Time elapsed: 15.3s.
Cache hits: 29%. Commands: 56 (cached: 16, remote: 0, local: 40)
Tests finished: Pass 28. Fail 0. Fatal 0. Skip 0. Build failure 0
```

Reviewed By: sergeyfd

Differential Revision: D50156479

fbshipit-source-id: ec176021b72271f65b17b6f311007dd355d0a482
  • Loading branch information
vmagro authored and facebook-github-bot committed Oct 11, 2023
1 parent 732d86a commit 2cdd1aa
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 69 deletions.
11 changes: 11 additions & 0 deletions antlir/antlir2/testing/image_test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::fs::File;
use std::fs::Permissions;
use std::io::Write;
use std::os::fd::AsRawFd;
use std::os::fd::FromRawFd;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::PermissionsExt;
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::path::PathBuf;
Expand Down Expand Up @@ -158,6 +160,13 @@ fn main() -> Result<()> {
ctx.hostname(hostname);
}

// test output dirs/files need to be world-writable so that tests can run as
// unprivileged users that are not the build user
for path in args.test.output_dirs() {
std::fs::set_permissions(&path, Permissions::from_mode(0o777))
.with_context(|| format!("while making {} world-writable", path.display()))?;
}

if args.boot {
let container_stdout = container_stdout_file()?;
let (mut test_stdout, mut test_stderr) = make_log_files("test")?;
Expand Down Expand Up @@ -208,6 +217,7 @@ fn main() -> Result<()> {

writeln!(test_unit_dropin, "[Service]")?;

writeln!(test_unit_dropin, "User={}", args.user)?;
write!(test_unit_dropin, "WorkingDirectory=")?;
let cwd = std::env::current_dir().context("while getting cwd")?;
test_unit_dropin.write_all(cwd.as_os_str().as_bytes())?;
Expand Down Expand Up @@ -279,6 +289,7 @@ fn main() -> Result<()> {
Ok(())
}
} else {
ctx.user(args.user);
let mut cmd = args.test.into_inner_cmd().into_iter();
let mut isol = isolate(ctx.build())?.command(cmd.next().expect("must have program arg"))?;
isol.args(cmd);
Expand Down
88 changes: 32 additions & 56 deletions antlir/antlir2/testing/tests/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ load("//antlir/antlir2/testing:image_diff_test.bzl", "image_diff_test")
load("//antlir/antlir2/testing:image_rpms_test.bzl", "image_test_rpm_integrity", "image_test_rpm_names")
load("//antlir/antlir2/testing:image_test.bzl", "image_cpp_test", "image_python_test", "image_rust_test", "image_sh_test")
load("//antlir/antlir2/testing:test_that_should_fail.bzl", "sh_test_that_should_fail", "test_that_should_fail")
load("//antlir/bzl:build_defs.bzl", "third_party")
load("//antlir/bzl:systemd.bzl", "systemd")
load(":test.bzl", "test_variants")

image.layer(
name = "base",
Expand Down Expand Up @@ -37,62 +39,36 @@ image.layer(
flavor = "//antlir/antlir2/test_images:test-image-flavor",
)

[
[
image_cpp_test(
name = "test-cpp" + ("-booted" if boot else "") + ("-requires-units" if boot == "wait-default" else ""),
srcs = ["test.cpp"],
boot = bool(boot),
boot_requires_units = ["default.target"] if boot == "wait-default" else None,
env = {
"ANTLIR2_TEST": "1",
"BOOT": str(boot),
},
layer = ":base",
supports_static_listing = False,
),
image_python_test(
name = "test-py" + ("-booted" if boot else "") + ("-requires-units" if boot == "wait-default" else ""),
srcs = ["test.py"],
boot = bool(boot),
boot_requires_units = ["default.target"] if boot == "wait-default" else None,
env = {
"ANTLIR2_TEST": "1",
"BOOT": str(boot),
},
layer = ":base",
),
image_rust_test(
name = "test-rs" + ("-booted" if boot else "") + ("-requires-units" if boot == "wait-default" else ""),
srcs = ["test.rs"],
boot = bool(boot),
boot_requires_units = ["default.target"] if boot == "wait-default" else None,
crate = "test_rs",
crate_root = "test.rs",
env = {
"ANTLIR2_TEST": "1",
"BOOT": str(boot),
},
layer = ":base",
),
image_sh_test(
name = "test-sh" + ("-booted" if boot else "") + ("-requires-units" if boot == "wait-default" else ""),
boot = bool(boot),
boot_requires_units = ["default.target"] if boot == "wait-default" else None,
env = {
"ANTLIR2_TEST": "1",
"BOOT": str(boot),
},
layer = ":base",
test = "test.sh",
),
]
for boot in [
False,
True,
"wait-default",
]
]
test_variants(
srcs = ["test.cpp"],
lang = "cpp",
supports_static_listing = False,
test_rule = image_cpp_test,
)

test_variants(
srcs = ["test.py"],
lang = "py",
test_rule = image_python_test,
)

test_variants(
srcs = ["test.rs"],
crate = "test_rs",
crate_root = "test.rs",
lang = "rust",
test_rule = image_rust_test,
deps = [third_party.library(
"whoami",
platform = "rust",
)],
)

test_variants(
lang = "sh",
test = "test.sh",
test_rule = image_sh_test,
)

image_python_test(
name = "test-hostname",
Expand Down
28 changes: 28 additions & 0 deletions antlir/antlir2/testing/tests/test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

def test_variants(
*,
test_rule,
lang: str,
layer: str = ":base",
**kwargs):
for boot in [True, False, "wait-default"]:
name = "test-" + lang + ("-booted" if boot else "")
name = name + ("-requires-units" if boot == "wait-default" else "")
for user in ["root", "nobody"]:
test_rule(
name = name + ("-" + user if user != "root" else ""),
boot = bool(boot),
boot_requires_units = ["default.target"] if boot == "wait-default" else None,
run_as_user = user,
layer = layer,
env = {
"ANTLIR2_TEST": "1",
"BOOT": str(boot),
"TEST_USER": user,
},
**kwargs
)
8 changes: 6 additions & 2 deletions antlir/antlir2/testing/tests/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
*/

#include <gtest/gtest.h>
#include <pwd.h>
#include <unistd.h>

TEST(CppTest, TestIsRoot) {
EXPECT_EQ(getuid(), 0);
TEST(CppTest, TestUser) {
auto uid = geteuid();
auto pw = getpwuid(uid);
EXPECT_TRUE(pw);
EXPECT_STREQ(pw->pw_name, std::getenv("TEST_USER"));
}

TEST(CppTest, TestEnvPropagated) {
Expand Down
9 changes: 7 additions & 2 deletions antlir/antlir2/testing/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
# LICENSE file in the root directory of this source tree.

import os
import pwd
import unittest


class Test(unittest.TestCase):
def test_is_root(self) -> None:
self.assertEqual(0, os.getuid())
def test_user(self) -> None:
if os.environ["TEST_USER"] == "root":
self.assertEqual(0, os.getuid())
else:
ent = pwd.getpwuid(os.getuid())
self.assertEqual(ent.pw_name, os.environ["TEST_USER"])

def test_env_propagated(self) -> None:
self.assertEqual("1", os.getenv("ANTLIR2_TEST"))
11 changes: 4 additions & 7 deletions antlir/antlir2/testing/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/

#[link(name = "c")]
extern "C" {
fn geteuid() -> u32;
}

#[test]
fn is_root() {
assert_eq!(0, unsafe { geteuid() });
fn user() {
let expected = std::env::var("TEST_USER").expect("TEST_USER not set");
let actual = whoami::username();
assert_eq!(expected, actual);
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions antlir/antlir2/testing/tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

set -ex

if [ "$UID" != "0" ]; then
echo "Not root!"
if [ "$(id -nu)" != "$TEST_USER" ]; then
echo "expected to run as $TEST_USER but am $(id -nu)"
exit 1
fi

Expand Down

0 comments on commit 2cdd1aa

Please sign in to comment.