1
0
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:
Brent Baude
2015-12-15 16:41:48 -06:00
parent b8159d13b1
commit f7a38d4e44
7 changed files with 128 additions and 25 deletions

View File

@@ -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)

View File

@@ -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
View File

@@ -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

View File

@@ -207,6 +207,7 @@ _atomic_top() {
--optional
-o
-d
-n
"
local all_options="$options_with_args"
[ "$command" = "top" ] && all_options="$all_options"

View File

@@ -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
View 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
View 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