mirror of
https://github.com/projectatomic/atomic.git
synced 2026-02-05 18:45:01 +01:00
Add tests for Atomic diff and top
Basic tests for atomic diff and top which should catch basic code regressions. In top.py, added -n for number of iterations. And added tty detection so that tests can pass in a jenkins environment where there is no tty.
This commit is contained in:
@@ -1031,19 +1031,6 @@ class AtomicDocker(docker.Client):
|
||||
A class based on the docker client class with custom APIs specifically for
|
||||
atomic
|
||||
"""
|
||||
def atomic_top(self, container, ps_args=None):
|
||||
"""
|
||||
Same as the docker top API but allows passing of ps args
|
||||
:param container: container ID
|
||||
:param ps_args: custom ps args
|
||||
:return:
|
||||
"""
|
||||
u = self._url("/containers/{0}/top".format(container))
|
||||
params = {}
|
||||
if ps_args is not None:
|
||||
params['ps_args'] = ps_args
|
||||
return self._result(self._get(u, params=params), True)
|
||||
|
||||
def remote_inspect(self, image_id):
|
||||
return self._result(self._get(self._url("/images/{0}/json?remote=1".
|
||||
format(image_id))), True)
|
||||
|
||||
@@ -5,6 +5,7 @@ import tty
|
||||
import sys
|
||||
import termios
|
||||
import select
|
||||
from os import isatty
|
||||
from operator import itemgetter
|
||||
|
||||
|
||||
@@ -86,11 +87,15 @@ class Top(Atomic):
|
||||
"""
|
||||
# Activate optional columns
|
||||
self._activate_optionals()
|
||||
|
||||
# Do we have a tty?
|
||||
# Can run ./atomic top <&- to replicate no tty
|
||||
has_tty = isatty(0)
|
||||
# Set up terminal, input handling
|
||||
fd = sys.stdin.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
if has_tty:
|
||||
fd = sys.stdin.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
sort_vals = [x['character'].upper() for x in self.headers if x['active'] and x['sort']]
|
||||
counter = 0
|
||||
while True:
|
||||
proc_info = []
|
||||
if len(self.args.containers) < 1:
|
||||
@@ -100,14 +105,15 @@ class Top(Atomic):
|
||||
for cid in con_ids:
|
||||
proc_info += self.get_pids_by_container(cid)
|
||||
# Reset screen
|
||||
if not self.DEBUG:
|
||||
if not self.DEBUG and has_tty:
|
||||
util.writeOut("\033c")
|
||||
sorted_info = self.reformat_ps_info(proc_info)
|
||||
self._set_dynamic_column_widths(sorted_info)
|
||||
self.output_top(sorted_info)
|
||||
tty.setraw(sys.stdin.fileno())
|
||||
if has_tty:
|
||||
tty.setraw(sys.stdin.fileno())
|
||||
i, ii, iii = select.select([sys.stdin], [], [], self.args.d)
|
||||
if i:
|
||||
if i and has_tty:
|
||||
ch = sys.stdin.read(1)
|
||||
# Detect 'q' or Cntrl-c
|
||||
if ch.upper() == 'q'.upper() or ord(ch) == 3:
|
||||
@@ -120,7 +126,11 @@ class Top(Atomic):
|
||||
None and header['character'].upper() == ch.upper()), False)
|
||||
|
||||
# reset terminal
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
if has_tty:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
counter += 1
|
||||
if counter == self.args.n:
|
||||
raise SystemExit
|
||||
|
||||
def get_pids_by_container(self, con_id):
|
||||
"""
|
||||
@@ -138,8 +148,7 @@ class Top(Atomic):
|
||||
# Assemble the ps args
|
||||
ps_args = [header['ps_opt']for header in sorted(self.headers, key=itemgetter('index')) if header['ps_opt']
|
||||
is not None and header['active']]
|
||||
con_procs = self.AD.atomic_top(con_id, ps_args="o {}".format(",".join(ps_args)))
|
||||
|
||||
con_procs = self.AD.top(con_id, ps_args="-o{}".format(",".join(ps_args)))
|
||||
# Set the column header titles one-time
|
||||
if self.titles is None:
|
||||
self.titles = con_procs['Titles']
|
||||
|
||||
9
atomic
9
atomic
@@ -93,6 +93,14 @@ def add_opt(sub):
|
||||
sub.add_argument("--opt2", dest="opt2",help=argparse.SUPPRESS)
|
||||
sub.add_argument("--opt3", dest="opt3",help=argparse.SUPPRESS)
|
||||
|
||||
|
||||
def check_negative(value):
|
||||
ivalue = int(value)
|
||||
if ivalue < 1:
|
||||
raise argparse.ArgumentTypeError("%s must be a positive integer value greater than 0." % value)
|
||||
return ivalue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if os.geteuid() != 0:
|
||||
exit("%s needs to be run as root." % sys.argv[0] )
|
||||
@@ -423,6 +431,7 @@ if __name__ == '__main__':
|
||||
topp.set_defaults(_class=Top, func='atomic_top')
|
||||
topp.add_argument("-d", type=int, default=1, help=_("Interval (secs) to refresh process information"))
|
||||
topp.add_argument("-o", "--optional", help=_("Additional fields to display"), nargs='*', choices=['time', 'stime', 'ppid'])
|
||||
topp.add_argument("-n", help=_("Number of iterations"), type=check_negative)
|
||||
topp.add_argument("containers", nargs="*", help=_("list of containers to monitor, leave blank for all"))
|
||||
|
||||
# atomic uninstall
|
||||
|
||||
@@ -207,6 +207,7 @@ _atomic_top() {
|
||||
--optional
|
||||
-o
|
||||
-d
|
||||
-n
|
||||
"
|
||||
local all_options="$options_with_args"
|
||||
[ "$command" = "top" ] && all_options="$all_options"
|
||||
|
||||
@@ -6,7 +6,7 @@ atomic-top - Run a top-like list of active container processes
|
||||
# SYNOPSIS
|
||||
**atomic top**
|
||||
[**-h**|**--help**]
|
||||
[**-d**][**-o, --optional=[time, stime, ppid]**]
|
||||
[**-d**][**-o, --optional=[time, stime, ppid]**][**-n**]
|
||||
[Containers to monitor]
|
||||
|
||||
# DESCRIPTION
|
||||
@@ -28,6 +28,9 @@ Like top, you can exit the interactive view and return to the command line, use
|
||||
Define the interval in seconds on which you want to refresh the process information. The interval should be an
|
||||
integer greater than 0. The default interval is set to 1.
|
||||
|
||||
**-n**
|
||||
The number of iterations. Must be greater than 0.
|
||||
|
||||
**-o** **--optional**
|
||||
Add more fields of data to collect for each process. The fields resemble fields commonly used by
|
||||
ps -o. They currently are: [time, stime, ppid]
|
||||
@@ -37,9 +40,9 @@ Monitor processes with default fields.
|
||||
|
||||
atomic top
|
||||
|
||||
Monitor processes with default fields on a 5 second interval.
|
||||
Monitor processes with default fields on a 5 second interval for 3 interations
|
||||
|
||||
atomic top -d 5
|
||||
atomic top -d 5 -n 3
|
||||
|
||||
Monitor processes and add in the data for the parent PIDs.
|
||||
|
||||
|
||||
48
tests/integration/test_diff.sh
Executable file
48
tests/integration/test_diff.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash -x
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
# Test scripts run with PWD=tests/..
|
||||
|
||||
# The test harness exports some variables into the environment during
|
||||
# testing: PYTHONPATH (python module import path
|
||||
# WORK_DIR (a directory that is safe to modify)
|
||||
# DOCKER (the docker executable location)
|
||||
# ATOMIC (an invocation of 'atomic' which measures code coverage)
|
||||
# SECRET (a generated sha256 hash inserted into test containers)
|
||||
|
||||
# In addition, the test harness creates some images for use in testing.
|
||||
# See tests/test-images/
|
||||
|
||||
setup () {
|
||||
# Perform setup routines here.
|
||||
IMAGE="atomic-test-1"
|
||||
id1=`${DOCKER} create ${IMAGE} /bin/true`
|
||||
id2=`${DOCKER} create ${IMAGE} rpm -e vim-minimal`
|
||||
${DOCKER} start ${id2}
|
||||
|
||||
}
|
||||
|
||||
teardown () {
|
||||
# Cleanup your test data.
|
||||
set +e
|
||||
${DOCKER} rm ${id1}
|
||||
${DOCKER} rm ${id2}
|
||||
set -e
|
||||
}
|
||||
# Utilize exit traps for cleanup wherever possible. Additional cleanup
|
||||
# logic can be added to a "cleanup stack", by cascading function calls
|
||||
# within traps. See tests/integration/test_mount.sh for an example.
|
||||
trap teardown EXIT
|
||||
|
||||
setup
|
||||
|
||||
OUTPUT=$(/bin/true)
|
||||
|
||||
# Test atomic diff for files and RPMs
|
||||
${ATOMIC} diff -r -v ${id1} ${id2} 1>/dev/null
|
||||
|
||||
# Test atomic diff with RPMs and output to json
|
||||
${ATOMIC} diff -r --json ${id1} ${id2} 1>/dev/null
|
||||
|
||||
|
||||
46
tests/integration/test_top.sh
Executable file
46
tests/integration/test_top.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash -x
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
# Test scripts run with PWD=tests/..
|
||||
|
||||
# The test harness exports some variables into the environment during
|
||||
# testing: PYTHONPATH (python module import path
|
||||
# WORK_DIR (a directory that is safe to modify)
|
||||
# DOCKER (the docker executable location)
|
||||
# ATOMIC (an invocation of 'atomic' which measures code coverage)
|
||||
# SECRET (a generated sha256 hash inserted into test containers)
|
||||
|
||||
# In addition, the test harness creates some images for use in testing.
|
||||
# See tests/test-images/
|
||||
|
||||
setup () {
|
||||
# Perform setup routines here.
|
||||
IMAGE="atomic-test-1"
|
||||
id1=`${DOCKER} run -d ${IMAGE} /usr/bin/vi`
|
||||
id2=`${DOCKER} run -d ${IMAGE} /usr/bin/top`
|
||||
|
||||
}
|
||||
|
||||
teardown () {
|
||||
# Cleanup your test data.
|
||||
set +e
|
||||
${DOCKER} stop ${id1}
|
||||
${DOCKER} rm ${id1}
|
||||
${DOCKER} stop ${id2}
|
||||
${DOCKER} rm ${id2}
|
||||
set -e
|
||||
}
|
||||
# Utilize exit traps for cleanup wherever possible. Additional cleanup
|
||||
# logic can be added to a "cleanup stack", by cascading function calls
|
||||
# within traps. See tests/integration/test_mount.sh for an example.
|
||||
trap teardown EXIT
|
||||
|
||||
setup
|
||||
|
||||
OUTPUT=$(/bin/true)
|
||||
|
||||
${ATOMIC} top -n 1
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user