Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v8.x] Backport aix test fixes to v8.x #29599

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions test/addons/addon.status
@@ -0,0 +1,5 @@
prefix addons

[true] # This section applies to all platforms

[$system==aix]
32 changes: 31 additions & 1 deletion test/addons/stringbytes-external-exceed-max/binding.cc
Expand Up @@ -2,12 +2,42 @@
#include <node.h>
#include <v8.h>

#ifdef _AIX
// AIX allows over-allocation, and will SIGKILL when the allocated pages are
// used if there is not enough VM. Check for available space until
// out-of-memory. Don't allow more then some (large) proportion of it to be
// used for the test strings, so Node & V8 have some space for allocations.
#include <signal.h>
#include <sys/vminfo.h>

static void* Allowed(size_t size) {
blkcnt_t allowedBlocks = psdanger(SIGKILL);

if (allowedBlocks < 1) {
// Already OOM
return nullptr;
}
const size_t BYTES_PER_BLOCK = 512;
size_t allowed = (allowedBlocks * BYTES_PER_BLOCK * 4) / 5;
if (size < allowed) {
return malloc(size);
}
return nullptr;
}
#else
// Other systems also allow over-allocation, but this malloc-and-free approach
// seems to be working for them.
static void* Allowed(size_t size) {
return malloc(size);
}
#endif // _AIX

void EnsureAllocation(const v8::FunctionCallbackInfo<v8::Value> &args) {
v8::Isolate* isolate = args.GetIsolate();
uintptr_t size = args[0]->IntegerValue();
v8::Local<v8::Boolean> success;

void* buffer = malloc(size);
void* buffer = Allowed(size);
if (buffer) {
success = v8::Boolean::New(isolate, true);
free(buffer);
Expand Down
1 change: 1 addition & 0 deletions test/message/message.status
Expand Up @@ -16,3 +16,4 @@ prefix message

[$system==freebsd]

[$system==aix]
andrewhughes101 marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 0 additions & 4 deletions test/pseudo-tty/pseudo-tty.status
@@ -1,9 +1,5 @@
prefix pseudo-tty

[$system==aix]
# being investigated under https://github.com/nodejs/node/issues/9728
test-tty-wrap : FAIL, PASS

[$system==solaris]
# https://github.com/nodejs/node/pull/16225 - `ioctl(fd, TIOCGWINSZ)` seems
# to fail with EINVAL on SmartOS when `fd` is a pty from python's pty module.
Expand Down
98 changes: 98 additions & 0 deletions test/pseudo-tty/pty_helper.py
@@ -0,0 +1,98 @@
import errno
import os
import pty
import select
import signal
import sys
import termios

STDIN = 0
STDOUT = 1
STDERR = 2


def pipe(sfd, dfd):
try:
data = os.read(sfd, 256)
except OSError as e:
if e.errno != errno.EIO:
raise
return True # EOF

if not data:
return True # EOF

if dfd == STDOUT:
# Work around platform quirks. Some platforms echo ^D as \x04
# (AIX, BSDs) and some don't (Linux).
filt = lambda c: ord(c) > 31 or c in '\t\n\r\f'
data = filter(filt, data)

while data:
try:
n = os.write(dfd, data)
except OSError as e:
if e.errno != errno.EIO:
raise
return True # EOF
data = data[n:]


if __name__ == '__main__':
argv = sys.argv[1:]

# Make select() interruptable by SIGCHLD.
signal.signal(signal.SIGCHLD, lambda nr, _: None)

master_fd, slave_fd = pty.openpty()
assert master_fd > STDIN

mode = termios.tcgetattr(slave_fd)
# Don't translate \n to \r\n.
mode[1] = mode[1] & ~termios.ONLCR # oflag
# Disable ECHOCTL. It's a BSD-ism that echoes e.g. \x04 as ^D but it
# doesn't work on platforms like AIX and Linux. I checked Linux's tty
# driver and it's a no-op, the driver is just oblivious to the flag.
mode[3] = mode[3] & ~termios.ECHOCTL # lflag
termios.tcsetattr(slave_fd, termios.TCSANOW, mode)

pid = os.fork()
if not pid:
os.setsid()
os.close(master_fd)

# Ensure the pty is a controlling tty.
name = os.ttyname(slave_fd)
fd = os.open(name, os.O_RDWR)
os.dup2(fd, slave_fd)
os.close(fd)

os.dup2(slave_fd, STDIN)
os.dup2(slave_fd, STDOUT)
os.dup2(slave_fd, STDERR)

if slave_fd > STDERR:
os.close(slave_fd)

os.execve(argv[0], argv, os.environ)
raise Exception('unreachable')

os.close(slave_fd)

fds = [STDIN, master_fd]
while fds:
try:
rfds, _, _ = select.select(fds, [], [])
except select.error as e:
if e[0] != errno.EINTR:
raise
if pid == os.waitpid(pid, os.WNOHANG)[0]:
break

if STDIN in rfds:
if pipe(STDIN, master_fd):
fds.remove(STDIN)

if master_fd in rfds:
if pipe(master_fd, STDOUT):
break
1 change: 1 addition & 0 deletions test/pseudo-tty/test-stdout-read.in
@@ -1 +1,2 @@
Hello!

1 change: 1 addition & 0 deletions test/pseudo-tty/test-stdout-read.out
@@ -1 +1,2 @@
Hello!
<Buffer 48 65 6c 6c 6f 21 0a>
15 changes: 9 additions & 6 deletions test/pseudo-tty/testcfg.py
Expand Up @@ -27,11 +27,13 @@

import test
import os
from os.path import join, exists, basename, isdir
from os.path import join, exists, basename, dirname, isdir
import re
import sys
import utils

FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
PTY_HELPER = join(dirname(__file__), 'pty_helper.py')

class TTYTestCase(test.TestCase):

Expand Down Expand Up @@ -105,17 +107,18 @@ def GetSource(self):
+ open(self.expected).read())

def RunCommand(self, command, env):
input = None
fd = None
if self.input is not None and exists(self.input):
input = open(self.input).read()
fd = os.open(self.input, os.O_RDONLY)
full_command = self.context.processor(command)
full_command = [sys.executable, PTY_HELPER] + full_command
output = test.Execute(full_command,
self.context,
self.context.GetTimeout(self.mode),
env,
faketty=True,
input=input)
self.Cleanup()
stdin=fd)
if fd is not None:
os.close(fd)
return test.TestOutput(self,
full_command,
output,
Expand Down
2 changes: 2 additions & 0 deletions test/sequential/sequential.status
Expand Up @@ -25,3 +25,5 @@ test-http2-settings-flood: PASS,FLAKY
[$system==freebsd]

[$system==aix]
# https://github.com/nodejs/node/pull/29054
test-buffer-creation-regression: SKIP
78 changes: 14 additions & 64 deletions tools/test.py
Expand Up @@ -640,15 +640,10 @@ def RunProcess(context, timeout, args, **rest):
prev_error_mode = Win32SetErrorMode(error_mode);
Win32SetErrorMode(error_mode | prev_error_mode);

faketty = rest.pop('faketty', False)
pty_out = rest.pop('pty_out')

process = subprocess.Popen(
args = popen_args,
**rest
)
if faketty:
os.close(rest['stdout'])
if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE:
Win32SetErrorMode(prev_error_mode)
# Compute the end time - if the process crosses this limit we
Expand All @@ -660,28 +655,6 @@ def RunProcess(context, timeout, args, **rest):
# loop and keep track of whether or not it times out.
exit_code = None
sleep_time = INITIAL_SLEEP_TIME
output = ''
if faketty:
while True:
if time.time() >= end_time:
# Kill the process and wait for it to exit.
KillTimedOutProcess(context, process.pid)
exit_code = process.wait()
timed_out = True
break

# source: http://stackoverflow.com/a/12471855/1903116
# related: http://stackoverflow.com/q/11165521/1903116
try:
data = os.read(pty_out, 9999)
except OSError as e:
if e.errno != errno.EIO:
raise
break # EIO means EOF on some systems
else:
if not data: # EOF
break
output += data

while exit_code is None:
if (not end_time is None) and (time.time() >= end_time):
Expand All @@ -695,7 +668,7 @@ def RunProcess(context, timeout, args, **rest):
sleep_time = sleep_time * SLEEP_TIME_FACTOR
if sleep_time > MAX_SLEEP_TIME:
sleep_time = MAX_SLEEP_TIME
return (process, exit_code, timed_out, output)
return (process, exit_code, timed_out)


def PrintError(str):
Expand All @@ -717,29 +690,12 @@ def CheckedUnlink(name):
PrintError("os.unlink() " + str(e))
break

def Execute(args, context, timeout=None, env={}, faketty=False, disable_core_files=False, input=None):
if faketty:
import pty
(out_master, fd_out) = pty.openpty()
fd_in = fd_err = fd_out
pty_out = out_master

if input is not None:
# Before writing input data, disable echo so the input doesn't show
# up as part of the output.
import termios
attr = termios.tcgetattr(fd_in)
attr[3] = attr[3] & ~termios.ECHO
termios.tcsetattr(fd_in, termios.TCSADRAIN, attr)

os.write(pty_out, input)
os.write(pty_out, '\x04') # End-of-file marker (Ctrl+D)
else:
(fd_out, outname) = tempfile.mkstemp()
(fd_err, errname) = tempfile.mkstemp()
fd_in = 0
pty_out = None
def Execute(args, context, timeout=None, env=None, disable_core_files=False, stdin=None):
(fd_out, outname) = tempfile.mkstemp()
(fd_err, errname) = tempfile.mkstemp()

if env is None:
env = {}
env_copy = os.environ.copy()

# Remove NODE_PATH
Expand All @@ -758,28 +714,22 @@ def disableCoreFiles():
resource.setrlimit(resource.RLIMIT_CORE, (0,0))
preexec_fn = disableCoreFiles

(process, exit_code, timed_out, output) = RunProcess(
(process, exit_code, timed_out) = RunProcess(
context,
timeout,
args = args,
stdin = fd_in,
stdin = stdin,
stdout = fd_out,
stderr = fd_err,
env = env_copy,
faketty = faketty,
pty_out = pty_out,
preexec_fn = preexec_fn
)
if faketty:
os.close(out_master)
errors = ''
else:
os.close(fd_out)
os.close(fd_err)
output = file(outname).read()
errors = file(errname).read()
CheckedUnlink(outname)
CheckedUnlink(errname)
os.close(fd_out)
os.close(fd_err)
output = open(outname).read()
errors = open(errname).read()
CheckedUnlink(outname)
CheckedUnlink(errname)

return CommandOutput(exit_code, timed_out, output, errors)

Expand Down