@@ -44,6 +44,7 @@ FOLLY_GNU_DISABLE_WARNING("-Wdeprecated-declarations")
4444
4545using namespace folly;
4646using namespace std ::chrono_literals;
47+ using namespace std ::string_literals;
4748using namespace std ::string_view_literals;
4849
4950namespace std ::chrono {
@@ -1103,4 +1104,165 @@ TEST(SetUserGroupId, CanOverrideAndReportFailure) {
11031104 EXPECT_EQ (fmt::format (" {}\t {}\t {}\t {}" , gid, egid, gid, gid), gidline);
11041105}
11051106
1107+ TEST (SetLinuxCGroup, CanSetCGroupFdAbsent) {
1108+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1109+ auto cgdirfd = ::open (cgdir.path ().native ().c_str (), O_DIRECTORY | O_CLOEXEC);
1110+ auto cgdirfdGuard = folly::makeGuard ([&] { ::close (cgdirfd); });
1111+ auto options = Subprocess::Options ();
1112+ options.setLinuxCGroupFd (cgdirfd);
1113+ EXPECT_THROW (
1114+ Subprocess (std::vector{" /bin/true" s}, options), SubprocessSpawnError);
1115+ }
1116+
1117+ TEST (SetLinuxCGroup, CanSetCGroupFdAbsentIntoErrnum) {
1118+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1119+ auto cgdirfd = ::open (cgdir.path ().native ().c_str (), O_DIRECTORY | O_CLOEXEC);
1120+ auto cgdirfdGuard = folly::makeGuard ([&] { ::close (cgdirfd); });
1121+ auto options = Subprocess::Options ();
1122+ std::shared_ptr<int > emptysp;
1123+ int errnum = 0 ;
1124+ options.setLinuxCGroupFd (cgdirfd, std::shared_ptr<int >{emptysp, &errnum});
1125+ Subprocess proc (std::vector{" /bin/true" s}, options);
1126+ EXPECT_EQ (ENOENT, errnum) << ::strerror (errnum);
1127+ proc.wait ();
1128+ EXPECT_EQ (0 , proc.returnCode ().exitStatus ());
1129+ }
1130+
1131+ TEST (SetLinuxCGroup, CanSetCGroupFdPresent) {
1132+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1133+ auto cgdirfd = ::open (cgdir.path ().native ().c_str (), O_DIRECTORY | O_CLOEXEC);
1134+ auto cgdirfdGuard = folly::makeGuard ([&] { ::close (cgdirfd); });
1135+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1136+ ::creat (cgprocs.native().c_str(), 0755); // rm'd with cgdir
1137+ auto options = Subprocess::Options ();
1138+ options.setLinuxCGroupFd (cgdirfd);
1139+ Subprocess proc (std::vector{" /bin/true" s}, options);
1140+ std::string s;
1141+ EXPECT_TRUE (readFile (cgprocs.native ().c_str (), s));
1142+ EXPECT_EQ (" 0" , s);
1143+ proc.wait ();
1144+ }
1145+
1146+ TEST (SetLinuxCGroup, CanSetCGroupFdPresentIntoErrnum) {
1147+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1148+ auto cgdirfd = ::open (cgdir.path ().native ().c_str (), O_DIRECTORY | O_CLOEXEC);
1149+ auto cgdirfdGuard = folly::makeGuard ([&] { ::close (cgdirfd); });
1150+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1151+ ::creat (cgprocs.native().c_str(), 0755); // rm'd with cgdir
1152+ auto options = Subprocess::Options ();
1153+ std::shared_ptr<int > emptysp;
1154+ int errnum = 0 ;
1155+ options.setLinuxCGroupFd (cgdirfd, std::shared_ptr<int >{emptysp, &errnum});
1156+ Subprocess proc (std::vector{" /bin/true" s}, options);
1157+ EXPECT_EQ (0 , errnum) << ::strerror (errnum);
1158+ std::string s;
1159+ EXPECT_TRUE (readFile (cgprocs.native ().c_str (), s));
1160+ EXPECT_EQ (" 0" , s);
1161+ proc.wait ();
1162+ }
1163+
1164+ TEST (SetLinuxCGroup, CanSetCGroupFdPresentProcsNoOpen) {
1165+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1166+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1167+ ::creat (cgprocs.native().c_str(), 0); // rm'd with cgdir
1168+ auto cgdirfd = ::open (cgdir.path ().native ().c_str (), O_DIRECTORY | O_CLOEXEC);
1169+ auto cgdirfdGuard = folly::makeGuard ([&] { ::close (cgdirfd); });
1170+ auto options = Subprocess::Options ();
1171+ options.setLinuxCGroupFd (cgdirfd);
1172+ EXPECT_THROW (
1173+ Subprocess (std::vector{" /bin/true" s}, options), SubprocessSpawnError);
1174+ }
1175+
1176+ TEST (SetLinuxCGroup, CanSetCGroupFdPresentProcsNoOpenIntoErrnum) {
1177+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1178+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1179+ ::creat (cgprocs.native().c_str(), 0); // rm'd with cgdir
1180+ auto cgdirfd = ::open (cgdir.path ().native ().c_str (), O_DIRECTORY | O_CLOEXEC);
1181+ auto cgdirfdGuard = folly::makeGuard ([&] { ::close (cgdirfd); });
1182+ auto options = Subprocess::Options ();
1183+ std::shared_ptr<int > emptysp;
1184+ int errnum = 0 ;
1185+ options.setLinuxCGroupFd (cgdirfd, std::shared_ptr<int >{emptysp, &errnum});
1186+ Subprocess proc (std::vector{" /bin/true" s}, options);
1187+ EXPECT_EQ (EACCES, errnum) << ::strerror (errnum);
1188+ proc.wait ();
1189+ EXPECT_EQ (0 , proc.returnCode ().exitStatus ());
1190+ }
1191+
1192+ TEST (SetLinuxCGroup, CanSetCGroupPathAbsent) {
1193+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1194+ auto options = Subprocess::Options ();
1195+ options.setLinuxCGroupPath (cgdir.path ().string ());
1196+ EXPECT_THROW (
1197+ Subprocess (std::vector{" /bin/true" s}, options), SubprocessSpawnError);
1198+ }
1199+
1200+ TEST (SetLinuxCGroup, CanSetCGroupPathAbsentIntoErrnum) {
1201+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1202+ auto options = Subprocess::Options ();
1203+ std::shared_ptr<int > emptysp;
1204+ int errnum = 0 ;
1205+ options.setLinuxCGroupPath (
1206+ cgdir.path ().string (), std::shared_ptr<int >{emptysp, &errnum});
1207+ Subprocess proc (std::vector{" /bin/true" s}, options);
1208+ EXPECT_EQ (ENOENT, errnum) << ::strerror (errnum);
1209+ proc.wait ();
1210+ EXPECT_EQ (0 , proc.returnCode ().exitStatus ());
1211+ }
1212+
1213+ TEST (SetLinuxCGroup, CanSetCGroupPathPresent) {
1214+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1215+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1216+ ::creat (cgprocs.native().c_str(), 0755); // rm'd with cgdir
1217+ auto options = Subprocess::Options ();
1218+ options.setLinuxCGroupPath (cgdir.path ().string ());
1219+ Subprocess proc (std::vector{" /bin/true" s}, options);
1220+ std::string s;
1221+ EXPECT_TRUE (readFile (cgprocs.native ().c_str (), s));
1222+ EXPECT_EQ (" 0" , s);
1223+ proc.wait ();
1224+ }
1225+
1226+ TEST (SetLinuxCGroup, CanSetCGroupPathPresentIntoErrnum) {
1227+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1228+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1229+ ::creat (cgprocs.native().c_str(), 0755); // rm'd with cgdir
1230+ auto options = Subprocess::Options ();
1231+ std::shared_ptr<int > emptysp;
1232+ int errnum = 0 ;
1233+ options.setLinuxCGroupPath (
1234+ cgdir.path ().string (), std::shared_ptr<int >{emptysp, &errnum});
1235+ Subprocess proc (std::vector{" /bin/true" s}, options);
1236+ EXPECT_EQ (0 , errnum) << ::strerror (errnum);
1237+ std::string s;
1238+ EXPECT_TRUE (readFile (cgprocs.native ().c_str (), s));
1239+ EXPECT_EQ (" 0" , s);
1240+ proc.wait ();
1241+ }
1242+
1243+ TEST (SetLinuxCGroup, CanSetCGroupPathPresentProcsNoOpen) {
1244+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1245+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1246+ ::creat (cgprocs.native().c_str(), 0); // rm'd with cgdir
1247+ auto options = Subprocess::Options ();
1248+ options.setLinuxCGroupPath (cgdir.path ().string ());
1249+ EXPECT_THROW (
1250+ Subprocess (std::vector{" /bin/true" s}, options), SubprocessSpawnError);
1251+ }
1252+
1253+ TEST (SetLinuxCGroup, CanSetCGroupPathPresentProcsNoOpenIntoErrnum) {
1254+ folly::test::TemporaryDirectory cgdir; // not a real cgroup dir
1255+ auto cgprocs = cgdir.path () / " cgroup.procs" ;
1256+ ::creat (cgprocs.native().c_str(), 0); // rm'd with cgdir
1257+ auto options = Subprocess::Options ();
1258+ std::shared_ptr<int > emptysp;
1259+ int errnum = 0 ;
1260+ options.setLinuxCGroupPath (
1261+ cgdir.path ().string (), std::shared_ptr<int >{emptysp, &errnum});
1262+ Subprocess proc (std::vector{" /bin/true" s}, options);
1263+ EXPECT_EQ (EACCES, errnum) << ::strerror (errnum);
1264+ proc.wait ();
1265+ EXPECT_EQ (0 , proc.returnCode ().exitStatus ());
1266+ }
1267+
11061268#endif
0 commit comments