1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458:
<?php
declare(strict_types=1);
class Test_Module extends Module_Skeleton
{
public $exportedFunctions = array(
'*' => PRIVILEGE_ALL,
);
public function __construct()
{
parent::__construct();
if (!is_debug()) {
$this->exportedFunctions = array('*' => PRIVILEGE_NONE);
}
}
public function benchmark_all($iterations = 1000, $testclass = null)
{
if (!is_debug()) {
return error('benchmark only enabled in dev');
}
$methods = array();
if (is_null($testclass)) {
$my_class = __CLASS__;
} else {
$my_class = $testclass;
}
if (!class_exists($my_class)) {
return error("Unknown class `%s'", $my_class);
}
$my_method = __FUNCTION__;
$rfxn = new ReflectionClass($my_class);
$maxlen = 0;
foreach ($rfxn->getMethods(ReflectionMethod::IS_PUBLIC) as $m) {
$method = $m->name;
$class = $m->class;
if ($class === $my_class && $method !== $my_method) {
$methods[] = $method;
$maxlen = max($maxlen, strlen($method));
}
}
$header = 'Module ' . $my_class;
print $header . "\n" .
str_repeat('=', strlen($header)) . "\n";
foreach ($methods as $m) {
printf('%-' . $maxlen . 's: ', $m);
$start = microtime(true);
for ($i = 0, $n = $iterations; $i < $n; $i++) {
assert($ret = $this->$m());
}
$end = microtime(true);
$diff = ($end - $start);
printf("%.4fs (%.6fs)\n", $diff, $diff / $iterations);
}
print "\n";
return true;
}
public function exec_named_args()
{
$args = array(
'program' => 'echo',
'args' => 'Hello World!'
);
$proc = Util_Process_Safe::exec('%(program)s %(args)s %(args)s',
$args, array(1, 0)
);
return $proc['success'];
}
public function exec_no_args()
{
$proc = Util_Process::exec('echo "Hello"',
array(0)
);
return $proc['success'];
}
public function exec_fail()
{
$proc = Util_Process::exec('/bin/true', array(1));
return $proc['success'] == false;
}
public function exec_additional_args()
{
$args = array('echo', "'Hello World!'", 'test');
$proc = Util_Process::exec('%s %s', 'echo', "'Hello World!'", 'Test');
return $proc['success'];
}
public function exec_quotes()
{
$args = array("'Hello World!'", 'test');
$proc = Util_Process_Safe::exec('echo %s %s', $args);
print $proc['stdout'];
return $proc['success'];
}
public function backend_performance($n = 10000)
{
return $this->benchmark('test_backend_emitter', $n);
}
public function benchmark($func, int $iterations = 1000)
{
if (!is_debug()) {
return error('benchmark only enabled in dev');
}
if ($func instanceof \Closure) {
$fname = (new ReflectionFunction($func))->getName();
} else if (is_callable(array($this, $func))) {
$fname = $func;
$func = [$this, $func];
}
if (!is_callable($func)) {
return error("function `%s' is not callable", $fname);
}
gc_collect_cycles();
gc_mem_caches();
$bm = static function (Callable $func, string $fname) use ($iterations) {
print 'benchmark ' . $fname . "\r\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$func();
}
$end = microtime(true);
$delta = $end - $start;
printf("time: %.2f sec (%d rounds; %.4f ms each; %.2f per second)\n\n",
$delta,
$iterations,
$delta / $iterations * 1000,
$iterations / $delta
);
return $delta;
};
$bmf = $bm($func, $fname);
$bm = null;
return $bmf;
}
public function backend_emitter($args = '')
{
return $this->query('test_backend_collector', $args);
}
public function backend_collector($args = '')
{
return $args;
}
public function config_bm()
{
$this->compare('test_config', 'test_config2');
}
public function compare($func1, $func2, $iterations = 1000)
{
if (!is_debug()) {
return error('benchmark only enabled in dev');
}
if (!$func1 || !$func2) {
return error('need 2 functions to compare');
}
$mem = memory_get_usage();
$bmf1 = $this->benchmark($func1, $iterations);
$bmf2 = $this->benchmark($func2, $iterations);
$ret = 0;
if ($bmf1 < $bmf2) {
printf('%s is quicker than %s ', $func1, $func2);
$diff = abs($bmf1 - $bmf2);
$diffp = $diff / $bmf2;
$ret = 1;
} else {
printf('%s is quicker than %s ', $func2, $func1);
$diff = abs($bmf2 - $bmf1);
$diffp = $diff / $bmf1;
$ret = -1;
}
printf("by %.2f%%\n\n", $diffp * 100);
printf("Mem usage: %.2f bytes\n", memory_get_usage() - $mem);
return;
}
public function config($conf = null)
{
$conf = $this->getAuthContext()->conf('ipinfo');
return "[DEFAULT]\n" . Util_Conf::build_ini($conf);
}
public function config2($conf = null)
{
$conf = $this->getAuthContext()->conf('ipinfo');
$data = '[DEFAULT]' . "\n";
foreach ($conf as $srvc_var => $srvc_val) {
$data .= $srvc_var . ' = ' . (!is_array($srvc_val) ? $srvc_val : (!$srvc_val ? '[]' : '[\'' . implode('\', \'',
array_unique($srvc_val)) . '\']')) . "\n";
}
return $data;
}
public function sudo()
{
if (!IS_CLI) {
return $this->query('test_sudo');
}
$args = array('user' => 'debug');
if ($this->permission_level & PRIVILEGE_ADMIN) {
$args['domain'] = 'debug.com';
}
$ret = Util_Process_Sudo::exec('id',
$args);
return $ret;
}
public function fn_decompose($cmd)
{
return Util_Process::decompose($cmd);
}
public function mail()
{
$address = $this->common_get_email() ?? Crm_Module::COPY_ADMIN;
$template = \BladeLite::factory('views/email');
$html = $template->make('simple',
[
'msg' => 'This is a test email from your panel!' .
"\n\nPanel login source: " . \Auth_Redirect::getPreferredUri()
]
)->render();
$opts = array(
'html_charset' => 'utf-8',
'text_charset' => 'utf-8'
);
$from = \Crm_Module::FROM_NAME . ' <' . \Crm_Module::FROM_ADDRESS . '>';
$headers = array(
'Sender' => $from,
'From' => $from
);
$mime = new Mail_Mime($opts);
$mime->setHTMLBody($html);
$mime->setTXTBody(strip_tags($html));
$headers = $mime->txtHeaders($headers);
$msg = $mime->get();
return Mail::send(
$address,
PANEL_BRAND . ' test',
$msg,
$headers
);
return info("Sent test email to `%s'", $address);
}
public function message_class(string $class, string $confirmation = 'Hello!') {
if (!\in_array($class, ['fatal', 'error', 'warning', 'info'], true)) {
return error("Unknown message class `%s'", $class);
}
return $class($confirmation);
}
public function sleep(int $time = 10)
{
if (!IS_CLI) {
return $this->query('test_sleep', $time);
}
sleep($time);
return true;
}
public function now()
{
return date('r');
}
public function context_performance()
{
if (!$this->permission_level & PRIVILEGE_SITE) {
return error('Context requires site admin privileges');
}
$oldrep = \Error_Reporter::set_verbose(0);
$user = \Opcenter\Auth\Password::generate(8, 'a-z');
if (!$this->user_add($user, 'randompassword12345')) {
return error('Failed to create user');
}
\assert(spl_object_hash(\Auth::context($user, $this->site)) !== spl_object_hash(\Auth::context($user, $this->site)), 'Context uniqueness');
$this->benchmark(function () use ($user) {
\Auth::context($user, $this->site);
});
$this->user_delete($user);
\Error_Reporter::clear_buffer();
\Error_Reporter::set_verbose($oldrep);
}
public function metrics(string $attr = null)
{
if (!TELEMETRY_ENABLED) {
return error('[telemetry] => enabled is off in config.ini');
}
$pg = PostgreSQL::pdo();
$query = "SELECT TIME_BUCKET('5 minute', ts), name, label, value FROM metrics " .
'JOIN metric_attributes USING (attr_id) WHERE site_id = ' . $this->site_id . " AND ts >= NOW() - '1 day'::INTERVAL";
if ($attr) {
$query .= ' AND name = ' . $pg->quote($attr);
}
$rs = $pg->query($query);
return $rs->fetchAll(PDO::FETCH_ASSOC);
}
public function sigchld_exit(int $code, bool $backend = true): int
{
if ($backend && !IS_CLI) {
return $this->query('test_sigchld_exit', $code, $backend);
}
$ret = \Util_Process_Safe::exec('exit %d', [$code]);
return $ret['return'];
}
}