diff --git a/README.md b/README.md index 4c6d4118..8bdbe1b6 100755 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ jc [OPTIONS] COMMAND The JSON output can be compact (default) or pretty formatted with the `-p` option. ### Parsers +- `--airport` enables the `airport -I` command parser (OSX) +- `--airport-s` enables the `airport -s` command parser (OSX) - `--arp` enables the `arp` command parser - `--blkid` enables the `blkid` command parser - `--crontab` enables the `crontab` command and file parser @@ -91,6 +93,7 @@ The JSON output can be compact (default) or pretty formatted with the `-p` optio - `--dig` enables the `dig` command parser - `--du` enables the `du` command parser - `--env` enables the `env` command parser +- `--file` enables the `file` command parser - `--free` enables the `free` command parser - `--fstab` enables the `/etc/fstab` file parser - `--group` enables the `/etc/group` file parser @@ -109,6 +112,7 @@ The JSON output can be compact (default) or pretty formatted with the `-p` optio - `--lsof` enables the `lsof` command parser - `--mount` enables the `mount` command parser - `--netstat` enables the `netstat` command parser +- `--ntpq` enables the `ntpq -p` command parser - `--passwd` enables the `/etc/passwd` file parser - `--pip-list` enables the `pip list` command parser - `--pip-show` enables the `pip show` command parser @@ -121,6 +125,7 @@ The JSON output can be compact (default) or pretty formatted with the `-p` optio - `--systemctl-lj` enables the `systemctl list-jobs` command parser - `--systemctl-ls` enables the `systemctl list-sockets` command parser - `--systemctl-luf` enables the `systemctl list-unit-files` command parser +- `--timedatectl` enables the `timedatectl status` command parser - `--uname` enables the `uname -a` command parser - `--uptime` enables the `uptime` command parser - `--w` enables the `w` command parser @@ -155,6 +160,7 @@ Tested on: - OSX 10.14.6 ## Acknowledgments +- CI automation and code optimizations from https://github.com/philippeitis - `ifconfig-parser` module from https://github.com/KnightWhoSayNi/ifconfig-parser - `xmltodict` module from https://github.com/martinblech/xmltodict by Martín Blech - `ruamel.yaml` library from https://pypi.org/project/ruamel.yaml by Anthon van der Neut @@ -162,6 +168,67 @@ Tested on: - Excellent constructive feedback from Ilya Sher (https://github.com/ilyash-b) ## Examples +### airport -I +``` +$ airport -I | jc --airport -p +{ + "agrctlrssi": -66, + "agrextrssi": 0, + "agrctlnoise": -90, + "agrextnoise": 0, + "state": "running", + "op_mode": "station", + "lasttxrate": 195, + "maxrate": 867, + "lastassocstatus": 0, + "802_11_auth": "open", + "link_auth": "wpa2-psk", + "bssid": "3c:37:86:15:ad:f9", + "ssid": "SnazzleDazzle", + "mcs": 0, + "channel": "48,80" +} +``` +### airport -s +``` +$ airport -s | jc --airport-s -p +[ + { + "ssid": "DIRECT-4A-HP OfficeJet 3830", + "bssid": "00:67:eb:2a:a7:3b", + "rssi": -90, + "channel": "6", + "ht": true, + "cc": "--", + "security": [ + "WPA2(PSK/AES/AES)" + ] + }, + { + "ssid": "Latitude38", + "bssid": "c0:ff:d5:d2:7a:f3", + "rssi": -85, + "channel": "11", + "ht": true, + "cc": "US", + "security": [ + "WPA2(PSK/AES/AES)" + ] + }, + { + "ssid": "xfinitywifi", + "bssid": "6e:e3:0e:b8:45:99", + "rssi": -83, + "channel": "11", + "ht": true, + "cc": "US", + "security": [ + "NONE" + ] + }, + ... +] +``` ### arp ``` $ arp | jc --arp -p # or: jc -p arp @@ -695,6 +762,41 @@ $ env | jc --env -p # or: jc -p env ... ] ``` +### file +``` +$ file * | jc --file -p +[ + { + "filename": "Applications", + "type": "directory" + }, + { + "filename": "another file with spaces", + "type": "empty" + }, + { + "filename": "argstest.py", + "type": "Python script text executable, ASCII text" + }, + { + "filename": "blkid-p.out", + "type": "ASCII text" + }, + { + "filename": "blkid-pi.out", + "type": "ASCII text, with very long lines" + }, + { + "filename": "cd_catalog.xml", + "type": "XML 1.0 document text, ASCII text, with CRLF line terminators" + }, + { + "filename": "centosserial.sh", + "type": "Bourne-Again shell script text executable, UTF-8 Unicode text" + }, + ... +] +``` ### free ``` $ free | jc --free -p # or: jc -p free @@ -1484,6 +1586,38 @@ $ sudo netstat -apee | jc --netstat -p # or: sudo jc -p netstat -apee ... ] ``` +### ntpq +``` +$ ntpq -p | jc --ntpq -p # or: jc -p ntpq -p +[ + { + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": 2, + "t": "u", + "when": 1, + "poll": 64, + "reach": 1, + "delay": 23.399, + "offset": -2.805, + "jitter": 2.131, + "state": null + }, + { + "remote": "mirror1.sjc02.s", + "refid": "216.218.254.202", + "st": 2, + "t": "u", + "when": 2, + "poll": 64, + "reach": 1, + "delay": 29.325, + "offset": 1.044, + "jitter": 4.069, + "state": null + } +] +``` ### /etc/passwd file ``` $ cat /etc/passwd | jc --passwd -p @@ -1991,6 +2125,20 @@ $ systemctl list-unit-files | jc --systemctl-luf -p # or: jc -p system ... ] ``` +### timedatectl status +``` +$ timedatectl | jc --timedatectl -p +{ + "local_time": "Tue 2020-03-10 17:53:21 PDT", + "universal_time": "Wed 2020-03-11 00:53:21 UTC", + "rtc_time": "Wed 2020-03-11 00:53:21", + "time_zone": "America/Los_Angeles (PDT, -0700)", + "ntp_enabled": true, + "ntp_synchronized": true, + "rtc_in_local_tz": false, + "dst_active": true +} +``` ### uname -a ``` $ uname -a | jc --uname -p # or: jc -p uname -a diff --git a/changelog.txt b/changelog.txt index 7b71da39..d8bff46b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,15 @@ jc changelog +20200311 v1.9.0 +- Added ntpq command parser +- Added timedatectl status command parser +- Added airport -I and airport -s command parser +- Added file command parser +- Optimized history command parser by https://github.com/philippeitis +- Magic syntax fix for certain edge cases + 20200308 v1.8.1 -- CLI and history parser optimizations by https://github.com/philippeitis +- CLI optimizations by https://github.com/philippeitis - Refactored magic syntax function and added tests (https://github.com/philippeitis) - Github actions for CI testing on multiple platforms by https://github.com/philippeitis - Updated ls parser to fix parsing error in OSX with -lR when there are empty folders diff --git a/docgen.sh b/docgen.sh index b37f7cde..f09c7f85 100755 --- a/docgen.sh +++ b/docgen.sh @@ -4,6 +4,8 @@ cd jc pydocmd simple jc+ > ../docs/readme.md pydocmd simple utils+ > ../docs/utils.md +pydocmd simple jc.parsers.airport+ > ../docs/parsers/airport.md +pydocmd simple jc.parsers.airport_s+ > ../docs/parsers/airport_s.md pydocmd simple jc.parsers.arp+ > ../docs/parsers/arp.md pydocmd simple jc.parsers.blkid+ > ../docs/parsers/blkid.md pydocmd simple jc.parsers.crontab+ > ../docs/parsers/crontab.md @@ -13,6 +15,7 @@ pydocmd simple jc.parsers.df+ > ../docs/parsers/df.md pydocmd simple jc.parsers.dig+ > ../docs/parsers/dig.md pydocmd simple jc.parsers.du+ > ../docs/parsers/du.md pydocmd simple jc.parsers.env+ > ../docs/parsers/env.md +pydocmd simple jc.parsers.file+ > ../docs/parsers/file.md pydocmd simple jc.parsers.free+ > ../docs/parsers/free.md pydocmd simple jc.parsers.fstab+ > ../docs/parsers/fstab.md pydocmd simple jc.parsers.group+ > ../docs/parsers/group.md @@ -31,6 +34,7 @@ pydocmd simple jc.parsers.lsmod+ > ../docs/parsers/lsmod.md pydocmd simple jc.parsers.lsof+ > ../docs/parsers/lsof.md pydocmd simple jc.parsers.mount+ > ../docs/parsers/mount.md pydocmd simple jc.parsers.netstat+ > ../docs/parsers/netstat.md +pydocmd simple jc.parsers.ntpq+ > ../docs/parsers/ntpq.md pydocmd simple jc.parsers.passwd+ > ../docs/parsers/passwd.md pydocmd simple jc.parsers.pip_list+ > ../docs/parsers/pip_list.md pydocmd simple jc.parsers.pip_show+ > ../docs/parsers/pip_show.md @@ -43,6 +47,7 @@ pydocmd simple jc.parsers.systemctl+ > ../docs/parsers/systemctl.md pydocmd simple jc.parsers.systemctl_lj+ > ../docs/parsers/systemctl_lj.md pydocmd simple jc.parsers.systemctl_ls+ > ../docs/parsers/systemctl_ls.md pydocmd simple jc.parsers.systemctl_luf+ > ../docs/parsers/systemctl_luf.md +pydocmd simple jc.parsers.timedatectl+ > ../docs/parsers/timedatectl.md pydocmd simple jc.parsers.uname+ > ../docs/parsers/uname.md pydocmd simple jc.parsers.uptime+ > ../docs/parsers/uptime.md pydocmd simple jc.parsers.w+ > ../docs/parsers/w.md diff --git a/docs/parsers/airport.md b/docs/parsers/airport.md new file mode 100644 index 00000000..3735793d --- /dev/null +++ b/docs/parsers/airport.md @@ -0,0 +1,109 @@ +# jc.parsers.airport +jc - JSON CLI output utility airport -I Parser + +Usage: + + specify --airport as the first argument if the piped input is coming from airport -I (OSX) + + This program can be found at: + /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport + +Compatibility: + + 'darwin' + +Examples: + + $ airport -I | jc --airport -p + { + "agrctlrssi": -66, + "agrextrssi": 0, + "agrctlnoise": -90, + "agrextnoise": 0, + "state": "running", + "op_mode": "station", + "lasttxrate": 195, + "maxrate": 867, + "lastassocstatus": 0, + "802_11_auth": "open", + "link_auth": "wpa2-psk", + "bssid": "3c:37:86:15:ad:f9", + "ssid": "SnazzleDazzle", + "mcs": 0, + "channel": "48,80" + } + + $ airport -I | jc --airport -p -r + { + "agrctlrssi": "-66", + "agrextrssi": "0", + "agrctlnoise": "-90", + "agrextnoise": "0", + "state": "running", + "op_mode": "station", + "lasttxrate": "195", + "maxrate": "867", + "lastassocstatus": "0", + "802_11_auth": "open", + "link_auth": "wpa2-psk", + "bssid": "3c:37:86:15:ad:f9", + "ssid": "SnazzleDazzle", + "mcs": "0", + "channel": "48,80" + } + +## info +```python +info(self, /, *args, **kwargs) +``` + +## process +```python +process(proc_data) +``` + +Final processing to conform to the schema. + +Parameters: + + proc_data: (dictionary) raw structured data to process + +Returns: + + Dictionary. Structured data with the following schema: + + { + "agrctlrssi": integer, + "agrextrssi": integer, + "agrctlnoise": integer, + "agrextnoise": integer, + "state": string, + "op_mode": string, + "lasttxrate": integer, + "maxrate": integer, + "lastassocstatus": integer, + "802_11_auth": string, + "link_auth": string, + "bssid": string, + "ssid": string, + "mcs": integer, + "channel": string + } + +## parse +```python +parse(data, raw=False, quiet=False) +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + diff --git a/docs/parsers/airport_s.md b/docs/parsers/airport_s.md new file mode 100644 index 00000000..992fc78d --- /dev/null +++ b/docs/parsers/airport_s.md @@ -0,0 +1,136 @@ +# jc.parsers.airport_s +jc - JSON CLI output utility airport -s Parser + +Usage: + + specify --airport as the first argument if the piped input is coming from airport -s (OSX) + + This program can be found at: + /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport + +Compatibility: + + 'darwin' + +Examples: + + $ airport -s | jc --airport-s -p + [ + { + "ssid": "DIRECT-4A-HP OfficeJet 3830", + "bssid": "00:67:eb:2a:a7:3b", + "rssi": -90, + "channel": "6", + "ht": true, + "cc": "--", + "security": [ + "WPA2(PSK/AES/AES)" + ] + }, + { + "ssid": "Latitude38", + "bssid": "c0:ff:d5:d2:7a:f3", + "rssi": -85, + "channel": "11", + "ht": true, + "cc": "US", + "security": [ + "WPA2(PSK/AES/AES)" + ] + }, + { + "ssid": "xfinitywifi", + "bssid": "6e:e3:0e:b8:45:99", + "rssi": -83, + "channel": "11", + "ht": true, + "cc": "US", + "security": [ + "NONE" + ] + }, + ... + ] + + $ airport -s | jc --airport -p -r + [ + { + "ssid": "DIRECT-F3-HP ENVY 5660 series", + "bssid": "b0:5a:da:6f:0a:d4", + "rssi": "-93", + "channel": "1", + "ht": "Y", + "cc": "--", + "security": "WPA2(PSK/AES/AES)" + }, + { + "ssid": "YouAreInfected-5", + "bssid": "5c:e3:0e:c2:85:da", + "rssi": "-85", + "channel": "36", + "ht": "Y", + "cc": "US", + "security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)" + }, + { + "ssid": "YuanFamily", + "bssid": "5c:e3:0e:b8:5f:9a", + "rssi": "-84", + "channel": "11", + "ht": "Y", + "cc": "US", + "security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)" + }, + ... + ] + +## info +```python +info(self, /, *args, **kwargs) +``` + +## process +```python +process(proc_data) +``` + +Final processing to conform to the schema. + +Parameters: + + proc_data: (dictionary) raw structured data to process + +Returns: + + List of dictionaries. Structured data with the following schema: + [ + { + "ssid": string, + "bssid": string, + "rssi": integer, + "channel": string, + "ht": boolean, + "cc": string, + "security": [ + string, + ] + } + ] + +## parse +```python +parse(data, raw=False, quiet=False) +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of dictionaries. Raw or processed structured data. + diff --git a/docs/parsers/file.md b/docs/parsers/file.md new file mode 100644 index 00000000..f7e4e7b1 --- /dev/null +++ b/docs/parsers/file.md @@ -0,0 +1,90 @@ +# jc.parsers.file +jc - JSON CLI output utility file command Parser + +Usage: + + specify --file as the first argument if the piped input is coming from file. + +Compatibility: + + 'linux', 'aix', 'freebsd', 'darwin' + +Examples: + + $ file * | jc --file -p + [ + { + "filename": "Applications", + "type": "directory" + }, + { + "filename": "another file with spaces", + "type": "empty" + }, + { + "filename": "argstest.py", + "type": "Python script text executable, ASCII text" + }, + { + "filename": "blkid-p.out", + "type": "ASCII text" + }, + { + "filename": "blkid-pi.out", + "type": "ASCII text, with very long lines" + }, + { + "filename": "cd_catalog.xml", + "type": "XML 1.0 document text, ASCII text, with CRLF line terminators" + }, + { + "filename": "centosserial.sh", + "type": "Bourne-Again shell script text executable, UTF-8 Unicode text" + }, + ... + ] + +## info +```python +info(self, /, *args, **kwargs) +``` + +## process +```python +process(proc_data) +``` + +Final processing to conform to the schema. + +Parameters: + + proc_data: (dictionary) raw structured data to process + +Returns: + + List of dictionaries. Structured data with the following schema: + + [ + { + "filename": string, + "type ": string + } + ] + +## parse +```python +parse(data, raw=False, quiet=False) +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of dictionaries. Raw or processed structured data. + diff --git a/docs/parsers/ntpq.md b/docs/parsers/ntpq.md new file mode 100644 index 00000000..fdd565ca --- /dev/null +++ b/docs/parsers/ntpq.md @@ -0,0 +1,235 @@ +# jc.parsers.ntpq +jc - JSON CLI output utility ntpq Parser + +Usage: + + specify --ntpq as the first argument if the piped input is coming from ntpq -p + +Compatibility: + + 'linux' + +Examples: + + $ ntpq -p | jc --ntpq -p + [ + { + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": 2, + "t": "u", + "when": 1, + "poll": 64, + "reach": 1, + "delay": 23.399, + "offset": -2.805, + "jitter": 2.131, + "state": null + }, + { + "remote": "ntp.wdc1.us.lea", + "refid": "130.133.1.10", + "st": 2, + "t": "u", + "when": null, + "poll": 64, + "reach": 1, + "delay": 93.053, + "offset": -0.807, + "jitter": 2.839, + "state": null + }, + { + "remote": "clock.team-cymr", + "refid": "204.9.54.119", + "st": 2, + "t": "u", + "when": null, + "poll": 64, + "reach": 1, + "delay": 70.337, + "offset": -2.909, + "jitter": 2.6, + "state": null + }, + { + "remote": "mirror1.sjc02.s", + "refid": "216.218.254.202", + "st": 2, + "t": "u", + "when": 2, + "poll": 64, + "reach": 1, + "delay": 29.325, + "offset": 1.044, + "jitter": 4.069, + "state": null, + } + ] + + $ ntpq -pn| jc --ntpq -p + [ + { + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": 2, + "t": "u", + "when": 66, + "poll": 64, + "reach": 377, + "delay": 22.69, + "offset": -0.392, + "jitter": 2.085, + "state": "+" + }, + { + "remote": "108.59.2.24", + "refid": "130.133.1.10", + "st": 2, + "t": "u", + "when": 63, + "poll": 64, + "reach": 377, + "delay": 90.805, + "offset": 2.84, + "jitter": 1.908, + "state": "-" + }, + { + "remote": "38.229.71.1", + "refid": "204.9.54.119", + "st": 2, + "t": "u", + "when": 64, + "poll": 64, + "reach": 377, + "delay": 68.699, + "offset": -0.61, + "jitter": 2.576, + "state": "+" + }, + { + "remote": "72.5.72.15", + "refid": "216.218.254.202", + "st": 2, + "t": "u", + "when": 63, + "poll": 64, + "reach": 377, + "delay": 22.654, + "offset": 0.231, + "jitter": 1.964, + "state": "*" + } + ] + + $ ntpq -pn| jc --ntpq -p -r + [ + { + "s": "+", + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": "2", + "t": "u", + "when": "66", + "poll": "64", + "reach": "377", + "delay": "22.690", + "offset": "-0.392", + "jitter": "2.085" + }, + { + "s": "-", + "remote": "108.59.2.24", + "refid": "130.133.1.10", + "st": "2", + "t": "u", + "when": "63", + "poll": "64", + "reach": "377", + "delay": "90.805", + "offset": "2.840", + "jitter": "1.908" + }, + { + "s": "+", + "remote": "38.229.71.1", + "refid": "204.9.54.119", + "st": "2", + "t": "u", + "when": "64", + "poll": "64", + "reach": "377", + "delay": "68.699", + "offset": "-0.610", + "jitter": "2.576" + }, + { + "s": "*", + "remote": "72.5.72.15", + "refid": "216.218.254.202", + "st": "2", + "t": "u", + "when": "63", + "poll": "64", + "reach": "377", + "delay": "22.654", + "offset": "0.231", + "jitter": "1.964" + } + ] + +## info +```python +info(self, /, *args, **kwargs) +``` + +## process +```python +process(proc_data) +``` + +Final processing to conform to the schema. + +Parameters: + + proc_data: (dictionary) raw structured data to process + +Returns: + + List of dictionaries. Structured data with the following schema: + + [ + { + "state": string, # space/~ converted to null + "remote": string, + "refid": string, + "st": integer, + "t": string, + "when": integer, # - converted to null + "poll": integer, + "reach": integer, + "delay": float, + "offset": float, + "jitter": float + }, + ] + + +## parse +```python +parse(data, raw=False, quiet=False) +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of dictionaries. Raw or processed structured data. + diff --git a/docs/parsers/timedatectl.md b/docs/parsers/timedatectl.md new file mode 100644 index 00000000..1f7f86b2 --- /dev/null +++ b/docs/parsers/timedatectl.md @@ -0,0 +1,87 @@ +# jc.parsers.timedatectl +jc - JSON CLI output utility timedatectl Parser + +Usage: + + specify --timedatectl as the first argument if the piped input is coming from timedatectl or timedatectl status + +Compatibility: + + 'linux' + +Examples: + + $ timedatectl | jc --timedatectl -p + { + "local_time": "Tue 2020-03-10 17:53:21 PDT", + "universal_time": "Wed 2020-03-11 00:53:21 UTC", + "rtc_time": "Wed 2020-03-11 00:53:21", + "time_zone": "America/Los_Angeles (PDT, -0700)", + "ntp_enabled": true, + "ntp_synchronized": true, + "rtc_in_local_tz": false, + "dst_active": true + } + + $ timedatectl | jc --timedatectl -p -r + { + "local_time": "Tue 2020-03-10 17:53:21 PDT", + "universal_time": "Wed 2020-03-11 00:53:21 UTC", + "rtc_time": "Wed 2020-03-11 00:53:21", + "time_zone": "America/Los_Angeles (PDT, -0700)", + "ntp_enabled": "yes", + "ntp_synchronized": "yes", + "rtc_in_local_tz": "no", + "dst_active": "yes" + } + +## info +```python +info(self, /, *args, **kwargs) +``` + +## process +```python +process(proc_data) +``` + +Final processing to conform to the schema. + +Parameters: + + proc_data: (dictionary) raw structured data to process + +Returns: + + Dictionary. Structured data with the following schema: + + { + "local_time": string, + "universal_time": string, + "rtc_time": string, + "time_zone": string, + "ntp_enabled": boolean, + "ntp_synchronized": boolean, + "system_clock_synchronized": boolean, + "systemd-timesyncd.service_active": boolean, + "rtc_in_local_tz": boolean, + "dst_active": boolean + } + +## parse +```python +parse(data, raw=False, quiet=False) +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + diff --git a/jc/cli.py b/jc/cli.py index a89d4eed..1b443609 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -13,7 +13,7 @@ import jc.utils class info(): - version = '1.8.1' + version = '1.9.0' description = 'jc cli output JSON conversion tool' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -22,6 +22,8 @@ class info(): __version__ = info.version parsers = [ + 'airport', + 'airport-s', 'arp', 'blkid', 'crontab', @@ -31,6 +33,7 @@ parsers = [ 'dig', 'du', 'env', + 'file', 'free', 'fstab', 'group', @@ -49,6 +52,7 @@ parsers = [ 'lsof', 'mount', 'netstat', + 'ntpq', 'passwd', 'pip-list', 'pip-show', @@ -61,6 +65,7 @@ parsers = [ 'systemctl-lj', 'systemctl-ls', 'systemctl-luf', + 'timedatectl', 'uname', 'uptime', 'w', @@ -194,20 +199,18 @@ def generate_magic_command(args): return False, None # correctly parse escape characters and spaces with shlex - args_given = " ".join(map(shlex.quote, args[1:])).split() + args_given = ' '.join(map(shlex.quote, args[1:])).split() options = [] # find the options - popped = 0 - for i, arg in enumerate(args_given): + for arg in list(args_given): # parser found - use standard syntax if arg.startswith('--'): return False, None # option found - populate option list elif arg.startswith('-'): - options.append(args_given.pop(i - popped)[1:]) - popped += 1 + options.extend(args_given.pop(0)[1:]) # command found if iterator didn't already stop - stop iterating else: diff --git a/jc/parsers/airport.py b/jc/parsers/airport.py new file mode 100644 index 00000000..ecc582e2 --- /dev/null +++ b/jc/parsers/airport.py @@ -0,0 +1,141 @@ +"""jc - JSON CLI output utility airport -I Parser + +Usage: + + specify --airport as the first argument if the piped input is coming from airport -I (OSX) + + This program can be found at: + /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport + +Compatibility: + + 'darwin' + +Examples: + + $ airport -I | jc --airport -p + { + "agrctlrssi": -66, + "agrextrssi": 0, + "agrctlnoise": -90, + "agrextnoise": 0, + "state": "running", + "op_mode": "station", + "lasttxrate": 195, + "maxrate": 867, + "lastassocstatus": 0, + "802_11_auth": "open", + "link_auth": "wpa2-psk", + "bssid": "3c:37:86:15:ad:f9", + "ssid": "SnazzleDazzle", + "mcs": 0, + "channel": "48,80" + } + + $ airport -I | jc --airport -p -r + { + "agrctlrssi": "-66", + "agrextrssi": "0", + "agrctlnoise": "-90", + "agrextnoise": "0", + "state": "running", + "op_mode": "station", + "lasttxrate": "195", + "maxrate": "867", + "lastassocstatus": "0", + "802_11_auth": "open", + "link_auth": "wpa2-psk", + "bssid": "3c:37:86:15:ad:f9", + "ssid": "SnazzleDazzle", + "mcs": "0", + "channel": "48,80" + } +""" +import jc.utils + + +class info(): + version = '1.0' + description = 'airport -I command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + # details = 'enter any other details here' + + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['darwin'] + magic_commands = ['airport -I'] + + +__version__ = info.version + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + Dictionary. Structured data with the following schema: + + { + "agrctlrssi": integer, + "agrextrssi": integer, + "agrctlnoise": integer, + "agrextnoise": integer, + "state": string, + "op_mode": string, + "lasttxrate": integer, + "maxrate": integer, + "lastassocstatus": integer, + "802_11_auth": string, + "link_auth": string, + "bssid": string, + "ssid": string, + "mcs": integer, + "channel": string + } + """ + # integer changes + int_list = ['agrctlrssi', 'agrextrssi', 'agrctlnoise', 'agrextnoise', + 'lasttxrate', 'maxrate', 'lastassocstatus', 'mcs'] + for key in proc_data: + if key in int_list: + try: + proc_data[key] = int(proc_data[key]) + except (ValueError): + proc_data[key] = None + + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + if not quiet: + jc.utils.compatibility(__name__, info.compatible) + + raw_output = {} + + for line in filter(None, data.splitlines()): + linedata = line.split(':', maxsplit=1) + raw_output[linedata[0].strip().lower().replace(' ', '_').replace('.', '_')] = linedata[1].strip() + + if raw: + return raw_output + else: + return process(raw_output) diff --git a/jc/parsers/airport_s.py b/jc/parsers/airport_s.py new file mode 100644 index 00000000..9f8e3e1b --- /dev/null +++ b/jc/parsers/airport_s.py @@ -0,0 +1,186 @@ +"""jc - JSON CLI output utility airport -s Parser + +Usage: + + specify --airport as the first argument if the piped input is coming from airport -s (OSX) + + This program can be found at: + /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport + +Compatibility: + + 'darwin' + +Examples: + + $ airport -s | jc --airport-s -p + [ + { + "ssid": "DIRECT-4A-HP OfficeJet 3830", + "bssid": "00:67:eb:2a:a7:3b", + "rssi": -90, + "channel": "6", + "ht": true, + "cc": "--", + "security": [ + "WPA2(PSK/AES/AES)" + ] + }, + { + "ssid": "Latitude38", + "bssid": "c0:ff:d5:d2:7a:f3", + "rssi": -85, + "channel": "11", + "ht": true, + "cc": "US", + "security": [ + "WPA2(PSK/AES/AES)" + ] + }, + { + "ssid": "xfinitywifi", + "bssid": "6e:e3:0e:b8:45:99", + "rssi": -83, + "channel": "11", + "ht": true, + "cc": "US", + "security": [ + "NONE" + ] + }, + ... + ] + + $ airport -s | jc --airport -p -r + [ + { + "ssid": "DIRECT-F3-HP ENVY 5660 series", + "bssid": "b0:5a:da:6f:0a:d4", + "rssi": "-93", + "channel": "1", + "ht": "Y", + "cc": "--", + "security": "WPA2(PSK/AES/AES)" + }, + { + "ssid": "YouAreInfected-5", + "bssid": "5c:e3:0e:c2:85:da", + "rssi": "-85", + "channel": "36", + "ht": "Y", + "cc": "US", + "security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)" + }, + { + "ssid": "YuanFamily", + "bssid": "5c:e3:0e:b8:5f:9a", + "rssi": "-84", + "channel": "11", + "ht": "Y", + "cc": "US", + "security": "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)" + }, + ... + ] +""" +import jc.utils +import jc.parsers.universal + + +class info(): + version = '1.0' + description = 'airport -s command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + # details = 'enter any other details here' + + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['darwin'] + magic_commands = ['airport -s'] + + +__version__ = info.version + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + List of dictionaries. Structured data with the following schema: + [ + { + "ssid": string, + "bssid": string, + "rssi": integer, + "channel": string, + "ht": boolean, + "cc": string, + "security": [ + string, + ] + } + ] + """ + for entry in proc_data: + + # integers + int_list = ['rssi'] + for key in int_list: + if key in entry: + try: + entry[key] = int(entry[key]) + except (ValueError): + entry[key] = None + + # booleans + bool_list = ['ht'] + for key in entry: + if key in bool_list: + try: + entry[key] = True if entry[key] == 'Y' else False + except (ValueError): + entry[key] = None + + if 'security' in entry: + entry['security'] = entry['security'].split() + + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of dictionaries. Raw or processed structured data. + """ + if not quiet: + jc.utils.compatibility(__name__, info.compatible) + + cleandata = data.splitlines() + + # fix headers + cleandata[0] = cleandata[0].lower() + cleandata[0] = cleandata[0].replace('-', '_') + cleandata[0] = cleandata[0].replace('security (auth/unicast/group)', 'security') + + # parse the data + raw_output = jc.parsers.universal.sparse_table_parse(cleandata) + + if raw: + return raw_output + else: + return process(raw_output) diff --git a/jc/parsers/file.py b/jc/parsers/file.py new file mode 100644 index 00000000..e72b4d5e --- /dev/null +++ b/jc/parsers/file.py @@ -0,0 +1,128 @@ +"""jc - JSON CLI output utility file command Parser + +Usage: + + specify --file as the first argument if the piped input is coming from file. + +Compatibility: + + 'linux', 'aix', 'freebsd', 'darwin' + +Examples: + + $ file * | jc --file -p + [ + { + "filename": "Applications", + "type": "directory" + }, + { + "filename": "another file with spaces", + "type": "empty" + }, + { + "filename": "argstest.py", + "type": "Python script text executable, ASCII text" + }, + { + "filename": "blkid-p.out", + "type": "ASCII text" + }, + { + "filename": "blkid-pi.out", + "type": "ASCII text, with very long lines" + }, + { + "filename": "cd_catalog.xml", + "type": "XML 1.0 document text, ASCII text, with CRLF line terminators" + }, + { + "filename": "centosserial.sh", + "type": "Bourne-Again shell script text executable, UTF-8 Unicode text" + }, + ... + ] +""" +import jc.utils +import jc.parsers.universal + + +class info(): + version = '1.0' + description = 'file command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['linux', 'aix', 'freebsd', 'darwin'] + magic_commands = ['file'] + + +__version__ = info.version + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + List of dictionaries. Structured data with the following schema: + + [ + { + "filename": string, + "type ": string + } + ] + """ + # No further processing + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of dictionaries. Raw or processed structured data. + """ + if not quiet: + jc.utils.compatibility(__name__, info.compatible) + + raw_output = [] + + warned = False + for line in filter(None, data.splitlines()): + linedata = line.rsplit(':', maxsplit=1) + + try: + filename = linedata[0].strip() + filetype = linedata[1].strip() + + raw_output.append( + { + 'filename': filename, + 'type': filetype + } + ) + except IndexError: + if not warned: + jc.utils.warning_message('Filenames with newline characters detected. Some filenames may be truncated.') + warned = True + + if raw: + return raw_output + else: + return process(raw_output) diff --git a/jc/parsers/history.py b/jc/parsers/history.py index 2624a520..d6ae4eca 100644 --- a/jc/parsers/history.py +++ b/jc/parsers/history.py @@ -80,21 +80,11 @@ def process(proc_data): # rebuild output for added semantic information processed = [] for k, v in proc_data.items(): - proc_line = {} - proc_line['line'] = k - proc_line['command'] = v + proc_line = { + 'line': int(k) if k.isdigit() else None, + 'command': v, + } processed.append(proc_line) - - for entry in processed: - int_list = ['line'] - for key in int_list: - if key in entry: - try: - key_int = int(entry[key]) - entry[key] = key_int - except (ValueError): - entry[key] = None - return processed @@ -121,17 +111,14 @@ def parse(data, raw=False, quiet=False): # split lines and clear out any non-ascii chars linedata = data.encode('ascii', errors='ignore').decode().splitlines() - # Clear any blank lines - cleandata = list(filter(None, linedata)) - - if cleandata: - for entry in cleandata: - try: - parsed_line = entry.split(maxsplit=1) - raw_output[parsed_line[0]] = parsed_line[1] - except IndexError: - # need to catch indexerror in case there is weird input from prior commands - pass + # Skip any blank lines + for entry in filter(None, linedata): + try: + parsed_line = entry.split(maxsplit=1) + raw_output[parsed_line[0]] = parsed_line[1] + except IndexError: + # need to catch indexerror in case there is weird input from prior commands + pass if raw: return raw_output diff --git a/jc/parsers/ntpq.py b/jc/parsers/ntpq.py new file mode 100644 index 00000000..2292f5e4 --- /dev/null +++ b/jc/parsers/ntpq.py @@ -0,0 +1,297 @@ +"""jc - JSON CLI output utility ntpq Parser + +Usage: + + specify --ntpq as the first argument if the piped input is coming from ntpq -p + +Compatibility: + + 'linux' + +Examples: + + $ ntpq -p | jc --ntpq -p + [ + { + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": 2, + "t": "u", + "when": 1, + "poll": 64, + "reach": 1, + "delay": 23.399, + "offset": -2.805, + "jitter": 2.131, + "state": null + }, + { + "remote": "ntp.wdc1.us.lea", + "refid": "130.133.1.10", + "st": 2, + "t": "u", + "when": null, + "poll": 64, + "reach": 1, + "delay": 93.053, + "offset": -0.807, + "jitter": 2.839, + "state": null + }, + { + "remote": "clock.team-cymr", + "refid": "204.9.54.119", + "st": 2, + "t": "u", + "when": null, + "poll": 64, + "reach": 1, + "delay": 70.337, + "offset": -2.909, + "jitter": 2.6, + "state": null + }, + { + "remote": "mirror1.sjc02.s", + "refid": "216.218.254.202", + "st": 2, + "t": "u", + "when": 2, + "poll": 64, + "reach": 1, + "delay": 29.325, + "offset": 1.044, + "jitter": 4.069, + "state": null, + } + ] + + $ ntpq -pn| jc --ntpq -p + [ + { + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": 2, + "t": "u", + "when": 66, + "poll": 64, + "reach": 377, + "delay": 22.69, + "offset": -0.392, + "jitter": 2.085, + "state": "+" + }, + { + "remote": "108.59.2.24", + "refid": "130.133.1.10", + "st": 2, + "t": "u", + "when": 63, + "poll": 64, + "reach": 377, + "delay": 90.805, + "offset": 2.84, + "jitter": 1.908, + "state": "-" + }, + { + "remote": "38.229.71.1", + "refid": "204.9.54.119", + "st": 2, + "t": "u", + "when": 64, + "poll": 64, + "reach": 377, + "delay": 68.699, + "offset": -0.61, + "jitter": 2.576, + "state": "+" + }, + { + "remote": "72.5.72.15", + "refid": "216.218.254.202", + "st": 2, + "t": "u", + "when": 63, + "poll": 64, + "reach": 377, + "delay": 22.654, + "offset": 0.231, + "jitter": 1.964, + "state": "*" + } + ] + + $ ntpq -pn| jc --ntpq -p -r + [ + { + "s": "+", + "remote": "44.190.6.254", + "refid": "127.67.113.92", + "st": "2", + "t": "u", + "when": "66", + "poll": "64", + "reach": "377", + "delay": "22.690", + "offset": "-0.392", + "jitter": "2.085" + }, + { + "s": "-", + "remote": "108.59.2.24", + "refid": "130.133.1.10", + "st": "2", + "t": "u", + "when": "63", + "poll": "64", + "reach": "377", + "delay": "90.805", + "offset": "2.840", + "jitter": "1.908" + }, + { + "s": "+", + "remote": "38.229.71.1", + "refid": "204.9.54.119", + "st": "2", + "t": "u", + "when": "64", + "poll": "64", + "reach": "377", + "delay": "68.699", + "offset": "-0.610", + "jitter": "2.576" + }, + { + "s": "*", + "remote": "72.5.72.15", + "refid": "216.218.254.202", + "st": "2", + "t": "u", + "when": "63", + "poll": "64", + "reach": "377", + "delay": "22.654", + "offset": "0.231", + "jitter": "1.964" + } + ] +""" +import jc.utils +import jc.parsers.universal + + +class info(): + version = '1.0' + description = 'ntpq -p command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['linux'] + magic_commands = ['ntpq'] + + +__version__ = info.version + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + List of dictionaries. Structured data with the following schema: + + [ + { + "state": string, # space/~ converted to null + "remote": string, + "refid": string, + "st": integer, + "t": string, + "when": integer, # - converted to null + "poll": integer, + "reach": integer, + "delay": float, + "offset": float, + "jitter": float + }, + ] + + """ + for entry in proc_data: + + if entry['s'] == '~': + entry['s'] = None + + entry['state'] = entry.pop('s') + + int_list = ['st', 'when', 'poll', 'reach'] + for key in int_list: + if key in entry: + try: + entry[key] = int(entry[key]) + except (ValueError): + entry[key] = None + + float_list = ['delay', 'offset', 'jitter'] + for key in float_list: + if key in entry: + try: + entry[key] = float(entry[key]) + except (ValueError): + entry[key] = None + + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of dictionaries. Raw or processed structured data. + """ + if not quiet: + jc.utils.compatibility(__name__, info.compatible) + + raw_output = [] + + cleandata = data.splitlines() + cleandata[0] = 's ' + cleandata[0] + cleandata[0] = cleandata[0].lower() + + # delete header delimiter + del cleandata[1] + + # separate first character with a space for easier parsing + for i, line in list(enumerate(cleandata[1:])): + if line[0] == ' ': + # fixup for no-state + cleandata[i + 1] = '~ ' + line[1:] + else: + # fixup - realign columns since we added the 's' column + cleandata[i + 1] = line[:1] + ' ' + line[1:] + + # fixup for occaisional ip/hostname fields with a space + cleandata[i + 1] = cleandata[i + 1].replace(' (', '_(') + + raw_output = jc.parsers.universal.simple_table_parse(cleandata) + + if raw: + return raw_output + else: + return process(raw_output) diff --git a/jc/parsers/timedatectl.py b/jc/parsers/timedatectl.py new file mode 100644 index 00000000..256e0c73 --- /dev/null +++ b/jc/parsers/timedatectl.py @@ -0,0 +1,122 @@ +"""jc - JSON CLI output utility timedatectl Parser + +Usage: + + specify --timedatectl as the first argument if the piped input is coming from timedatectl or timedatectl status + +Compatibility: + + 'linux' + +Examples: + + $ timedatectl | jc --timedatectl -p + { + "local_time": "Tue 2020-03-10 17:53:21 PDT", + "universal_time": "Wed 2020-03-11 00:53:21 UTC", + "rtc_time": "Wed 2020-03-11 00:53:21", + "time_zone": "America/Los_Angeles (PDT, -0700)", + "ntp_enabled": true, + "ntp_synchronized": true, + "rtc_in_local_tz": false, + "dst_active": true + } + + $ timedatectl | jc --timedatectl -p -r + { + "local_time": "Tue 2020-03-10 17:53:21 PDT", + "universal_time": "Wed 2020-03-11 00:53:21 UTC", + "rtc_time": "Wed 2020-03-11 00:53:21", + "time_zone": "America/Los_Angeles (PDT, -0700)", + "ntp_enabled": "yes", + "ntp_synchronized": "yes", + "rtc_in_local_tz": "no", + "dst_active": "yes" + } +""" +import jc.utils + + +class info(): + version = '1.0' + description = 'timedatectl status command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + # details = 'enter any other details here' + + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['linux'] + magic_commands = ['timedatectl', 'timedatectl status'] + + +__version__ = info.version + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + Dictionary. Structured data with the following schema: + + { + "local_time": string, + "universal_time": string, + "rtc_time": string, + "time_zone": string, + "ntp_enabled": boolean, + "ntp_synchronized": boolean, + "system_clock_synchronized": boolean, + "systemd-timesyncd.service_active": boolean, + "rtc_in_local_tz": boolean, + "dst_active": boolean + } + """ + # boolean changes + bool_list = ['ntp_enabled', 'ntp_synchronized', 'rtc_in_local_tz', 'dst_active', + 'system_clock_synchronized', 'systemd-timesyncd.service_active'] + for key in proc_data: + if key in bool_list: + try: + proc_data[key] = True if proc_data[key] == 'yes' else False + except (ValueError): + proc_data[key] = None + + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + if not quiet: + jc.utils.compatibility(__name__, info.compatible) + + raw_output = {} + + for line in filter(None, data.splitlines()): + linedata = line.split(':', maxsplit=1) + raw_output[linedata[0].strip().lower().replace(' ', '_')] = linedata[1].strip() + + if linedata[0].strip() == 'DST active': + break + + if raw: + return raw_output + else: + return process(raw_output) diff --git a/setup.py b/setup.py index 85fa9afb..16dfbee0 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ with open('README.md', 'r') as f: setuptools.setup( name='jc', - version='1.8.1', + version='1.9.0', author='Kelly Brazil', author_email='kellyjonbrazil@gmail.com', description='This tool serializes the output of popular command line tools and filetypes to structured JSON output.', diff --git a/tests/fixtures/centos-7.7/file.json b/tests/fixtures/centos-7.7/file.json new file mode 100644 index 00000000..914ca697 --- /dev/null +++ b/tests/fixtures/centos-7.7/file.json @@ -0,0 +1 @@ +[{"filename": "bin", "type": "directory"}, {"filename": "digout", "type": "ASCII text"}, {"filename": "file with spaces in the name", "type": "empty"}, {"filename": "git", "type": "directory"}, {"filename": "id-centos.out", "type": "ASCII text"}, {"filename": "ifcfg.json", "type": "ASCII text, with very long lines"}, {"filename": "ifconfig.out", "type": "ASCII text"}, {"filename": "iptables-tests", "type": "directory"}, {"filename": "journaljson", "type": "ASCII text, with very long lines"}, {"filename": "jp", "type": "ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped"}, {"filename": "jp_1.1.12_linux_x86_64.zip", "type": "Zip archive data, at least v2.0 to extract"}, {"filename": "lastb.out", "type": "ASCII text"}, {"filename": "lsblk-cols", "type": "UTF-8 Unicode text"}, {"filename": "psfile.txt", "type": "ASCII text, with very long lines"}, {"filename": "resizeterm.sh", "type": "Bourne-Again shell script, ASCII text executable"}, {"filename": "routeout", "type": "ASCII text"}, {"filename": "ss-aeep.out", "type": "ASCII text"}, {"filename": "ssout", "type": "ASCII text"}, {"filename": "systemctl.out", "type": "UTF-8 Unicode text"}, {"filename": "testfiles", "type": "directory"}, {"filename": "tmp", "type": "directory"}, {"filename": "top.out", "type": "ASCII text, with escape sequences"}, {"filename": "who-aH.out", "type": "ASCII text"}, {"filename": "who.out", "type": "ASCII text"}, {"filename": "whotext", "type": "ASCII text"}] diff --git a/tests/fixtures/centos-7.7/file.out b/tests/fixtures/centos-7.7/file.out new file mode 100644 index 00000000..4c615195 --- /dev/null +++ b/tests/fixtures/centos-7.7/file.out @@ -0,0 +1,25 @@ +bin: directory +digout: ASCII text +file with spaces in the name: empty +git: directory +id-centos.out: ASCII text +ifcfg.json: ASCII text, with very long lines +ifconfig.out: ASCII text +iptables-tests: directory +journaljson: ASCII text, with very long lines +jp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped +jp_1.1.12_linux_x86_64.zip: Zip archive data, at least v2.0 to extract +lastb.out: ASCII text +lsblk-cols: UTF-8 Unicode text +psfile.txt: ASCII text, with very long lines +resizeterm.sh: Bourne-Again shell script, ASCII text executable +routeout: ASCII text +ss-aeep.out: ASCII text +ssout: ASCII text +systemctl.out: UTF-8 Unicode text +testfiles: directory +tmp: directory +top.out: ASCII text, with escape sequences +who-aH.out: ASCII text +who.out: ASCII text +whotext: ASCII text diff --git a/tests/fixtures/centos-7.7/ntpq-p.json b/tests/fixtures/centos-7.7/ntpq-p.json new file mode 100644 index 00000000..1dbdd318 --- /dev/null +++ b/tests/fixtures/centos-7.7/ntpq-p.json @@ -0,0 +1 @@ +[{"state": null, "remote": "44.190.6.254", "refid": "127.67.113.92", "st": 2, "t": "u", "when": 1, "poll": 64, "reach": 1, "delay": 23.399, "offset": -2.805, "jitter": 2.131}, {"state": null, "remote": "ntp.wdc1.us.lea", "refid": "130.133.1.10", "st": 2, "t": "u", "when": null, "poll": 64, "reach": 1, "delay": 93.053, "offset": -0.807, "jitter": 2.839}, {"state": null, "remote": "clock.team-cymr", "refid": "204.9.54.119", "st": 2, "t": "u", "when": null, "poll": 64, "reach": 1, "delay": 70.337, "offset": -2.909, "jitter": 2.6}, {"state": null, "remote": "mirror1.sjc02.s", "refid": "216.218.254.202", "st": 2, "t": "u", "when": 2, "poll": 64, "reach": 1, "delay": 29.325, "offset": 1.044, "jitter": 4.069}] diff --git a/tests/fixtures/centos-7.7/ntpq-p.out b/tests/fixtures/centos-7.7/ntpq-p.out new file mode 100644 index 00000000..5cefcac5 --- /dev/null +++ b/tests/fixtures/centos-7.7/ntpq-p.out @@ -0,0 +1,6 @@ + remote refid st t when poll reach delay offset jitter +============================================================================== + 44.190.6.254 127.67.113.92 2 u 1 64 1 23.399 -2.805 2.131 + ntp.wdc1.us.lea 130.133.1.10 2 u - 64 1 93.053 -0.807 2.839 + clock.team-cymr 204.9.54.119 2 u - 64 1 70.337 -2.909 2.600 + mirror1.sjc02.s 216.218.254.202 2 u 2 64 1 29.325 1.044 4.069 diff --git a/tests/fixtures/centos-7.7/ntpq-pn.json b/tests/fixtures/centos-7.7/ntpq-pn.json new file mode 100644 index 00000000..2ad28cbf --- /dev/null +++ b/tests/fixtures/centos-7.7/ntpq-pn.json @@ -0,0 +1 @@ +[{"state": "+", "remote": "44.190.6.254", "refid": "127.67.113.92", "st": 2, "t": "u", "when": 66, "poll": 64, "reach": 377, "delay": 22.69, "offset": -0.392, "jitter": 2.085}, {"state": "-", "remote": "108.59.2.24", "refid": "130.133.1.10", "st": 2, "t": "u", "when": 63, "poll": 64, "reach": 377, "delay": 90.805, "offset": 2.84, "jitter": 1.908}, {"state": "+", "remote": "38.229.71.1", "refid": "204.9.54.119", "st": 2, "t": "u", "when": 64, "poll": 64, "reach": 377, "delay": 68.699, "offset": -0.61, "jitter": 2.576}, {"state": "*", "remote": "72.5.72.15", "refid": "216.218.254.202", "st": 2, "t": "u", "when": 63, "poll": 64, "reach": 377, "delay": 22.654, "offset": 0.231, "jitter": 1.964}] diff --git a/tests/fixtures/centos-7.7/ntpq-pn.out b/tests/fixtures/centos-7.7/ntpq-pn.out new file mode 100644 index 00000000..9bbce795 --- /dev/null +++ b/tests/fixtures/centos-7.7/ntpq-pn.out @@ -0,0 +1,6 @@ + remote refid st t when poll reach delay offset jitter +============================================================================== ++44.190.6.254 127.67.113.92 2 u 66 64 377 22.690 -0.392 2.085 +-108.59.2.24 130.133.1.10 2 u 63 64 377 90.805 2.840 1.908 ++38.229.71.1 204.9.54.119 2 u 64 64 377 68.699 -0.610 2.576 +*72.5.72.15 216.218.254.202 2 u 63 64 377 22.654 0.231 1.964 diff --git a/tests/fixtures/centos-7.7/timedatectl.json b/tests/fixtures/centos-7.7/timedatectl.json new file mode 100644 index 00000000..11d2bbce --- /dev/null +++ b/tests/fixtures/centos-7.7/timedatectl.json @@ -0,0 +1 @@ +{"local_time": "Tue 2020-03-10 17:53:21 PDT", "universal_time": "Wed 2020-03-11 00:53:21 UTC", "rtc_time": "Wed 2020-03-11 00:53:21", "time_zone": "America/Los_Angeles (PDT, -0700)", "ntp_enabled": true, "ntp_synchronized": true, "rtc_in_local_tz": false, "dst_active": true} diff --git a/tests/fixtures/centos-7.7/timedatectl.out b/tests/fixtures/centos-7.7/timedatectl.out new file mode 100644 index 00000000..c18e6768 --- /dev/null +++ b/tests/fixtures/centos-7.7/timedatectl.out @@ -0,0 +1,14 @@ + Local time: Tue 2020-03-10 17:53:21 PDT + Universal time: Wed 2020-03-11 00:53:21 UTC + RTC time: Wed 2020-03-11 00:53:21 + Time zone: America/Los_Angeles (PDT, -0700) + NTP enabled: yes +NTP synchronized: yes + RTC in local TZ: no + DST active: yes + Last DST change: DST began at + Sun 2020-03-08 01:59:59 PST + Sun 2020-03-08 03:00:00 PDT + Next DST change: DST ends (the clock jumps one hour backwards) at + Sun 2020-11-01 01:59:59 PDT + Sun 2020-11-01 01:00:00 PST diff --git a/tests/fixtures/osx-10.14.6/airport-I.json b/tests/fixtures/osx-10.14.6/airport-I.json new file mode 100644 index 00000000..f0155ef1 --- /dev/null +++ b/tests/fixtures/osx-10.14.6/airport-I.json @@ -0,0 +1 @@ +{"agrctlrssi": -66, "agrextrssi": 0, "agrctlnoise": -90, "agrextnoise": 0, "state": "running", "op_mode": "station", "lasttxrate": 195, "maxrate": 867, "lastassocstatus": 0, "802_11_auth": "open", "link_auth": "wpa2-psk", "bssid": "3c:37:86:15:ad:f9", "ssid": "SnazzleDazzle", "mcs": 0, "channel": "48,80"} diff --git a/tests/fixtures/osx-10.14.6/airport-I.out b/tests/fixtures/osx-10.14.6/airport-I.out new file mode 100644 index 00000000..e6eeb569 --- /dev/null +++ b/tests/fixtures/osx-10.14.6/airport-I.out @@ -0,0 +1,15 @@ + agrCtlRSSI: -66 + agrExtRSSI: 0 + agrCtlNoise: -90 + agrExtNoise: 0 + state: running + op mode: station + lastTxRate: 195 + maxRate: 867 +lastAssocStatus: 0 + 802.11 auth: open + link auth: wpa2-psk + BSSID: 3c:37:86:15:ad:f9 + SSID: SnazzleDazzle + MCS: 0 + channel: 48,80 diff --git a/tests/fixtures/osx-10.14.6/airport-s.json b/tests/fixtures/osx-10.14.6/airport-s.json new file mode 100644 index 00000000..5a6a49c2 --- /dev/null +++ b/tests/fixtures/osx-10.14.6/airport-s.json @@ -0,0 +1 @@ +[{"ssid": "DIRECT-4A-HP OfficeJet 3830", "bssid": "00:68:eb:2b:b7:3b", "rssi": -91, "channel": "6", "ht": true, "cc": "--", "security": ["WPA2(PSK/AES/AES)"]}, {"ssid": "xfinitywifi", "bssid": "6e:e3:0e:c1:74:df", "rssi": -87, "channel": "36", "ht": true, "cc": "US", "security": ["NONE"]}, {"ssid": "XFINITY", "bssid": "8e:e3:0e:c1:74:df", "rssi": -86, "channel": "36", "ht": true, "cc": "US", "security": ["WPA2(802.1x/AES/AES)"]}, {"ssid": "YouAreInfected-5", "bssid": "5c:e3:0e:c1:74:df", "rssi": -86, "channel": "36", "ht": true, "cc": "US", "security": ["WPA(PSK/AES,TKIP/TKIP)", "WPA2(PSK/AES,TKIP/TKIP)"]}, {"ssid": "xfinitywifi", "bssid": "6e:e3:0e:b8:55:8f", "rssi": -85, "channel": "11", "ht": true, "cc": "US", "security": ["NONE"]}, {"ssid": "xfinitywifi", "bssid": "6e:e3:0e:c1:74:de", "rssi": -79, "channel": "6", "ht": true, "cc": "US", "security": ["NONE"]}, {"ssid": "ngHub_319451N814D6D", "bssid": "04:a1:51:56:5c:eb", "rssi": -77, "channel": "11", "ht": true, "cc": "US", "security": ["WPA2(PSK/AES/AES)"]}, {"ssid": "YouAreInfected", "bssid": "5c:e3:0e:c1:74:de", "rssi": -76, "channel": "6", "ht": true, "cc": "US", "security": ["WPA(PSK/AES,TKIP/TKIP)", "WPA2(PSK/AES,TKIP/TKIP)"]}, {"ssid": "YuanFamily_Extender2G", "bssid": "a0:04:60:86:11:89", "rssi": -76, "channel": "11", "ht": true, "cc": "--", "security": ["WPA(PSK/AES,TKIP/TKIP)", "WPA2(PSK/AES,TKIP/TKIP)"]}, {"ssid": "YuanFamily", "bssid": "5c:e3:0e:b8:15:9f", "rssi": -73, "channel": "11", "ht": true, "cc": "US", "security": ["WPA(PSK/AES,TKIP/TKIP)", "WPA2(PSK/AES,TKIP/TKIP)"]}, {"ssid": "SnazzleDazzle", "bssid": "3c:37:86:15:fd:b5", "rssi": -70, "channel": "48", "ht": true, "cc": "US", "security": ["WPA2(PSK/AES/AES)"]}, {"ssid": "SnazzleDazzle", "bssid": "42:37:86:15:fd:b3", "rssi": -62, "channel": "3,+1", "ht": true, "cc": "US", "security": ["WPA2(PSK/AES/AES)"]}, {"ssid": "SnazzleDazzle", "bssid": "42:37:86:15:aa:f7", "rssi": -54, "channel": "3", "ht": true, "cc": "US", "security": ["WPA2(PSK/AES/AES)"]}, {"ssid": "SnazzleDazzle", "bssid": "3c:37:86:15:aa:f9", "rssi": -64, "channel": "48", "ht": true, "cc": "US", "security": ["WPA2(PSK/AES/AES)"]}] diff --git a/tests/fixtures/osx-10.14.6/airport-s.out b/tests/fixtures/osx-10.14.6/airport-s.out new file mode 100644 index 00000000..1f0254ce --- /dev/null +++ b/tests/fixtures/osx-10.14.6/airport-s.out @@ -0,0 +1,15 @@ + SSID BSSID RSSI CHANNEL HT CC SECURITY (auth/unicast/group) + DIRECT-4A-HP OfficeJet 3830 00:68:eb:2b:b7:3b -91 6 Y -- WPA2(PSK/AES/AES) + xfinitywifi 6e:e3:0e:c1:74:df -87 36 Y US NONE + XFINITY 8e:e3:0e:c1:74:df -86 36 Y US WPA2(802.1x/AES/AES) + YouAreInfected-5 5c:e3:0e:c1:74:df -86 36 Y US WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP) + xfinitywifi 6e:e3:0e:b8:55:8f -85 11 Y US NONE + xfinitywifi 6e:e3:0e:c1:74:de -79 6 Y US NONE + ngHub_319451N814D6D 04:a1:51:56:5c:eb -77 11 Y US WPA2(PSK/AES/AES) + YouAreInfected 5c:e3:0e:c1:74:de -76 6 Y US WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP) + YuanFamily_Extender2G a0:04:60:86:11:89 -76 11 Y -- WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP) + YuanFamily 5c:e3:0e:b8:15:9f -73 11 Y US WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP) + SnazzleDazzle 3c:37:86:15:fd:b5 -70 48 Y US WPA2(PSK/AES/AES) + SnazzleDazzle 42:37:86:15:fd:b3 -62 3,+1 Y US WPA2(PSK/AES/AES) + SnazzleDazzle 42:37:86:15:aa:f7 -54 3 Y US WPA2(PSK/AES/AES) + SnazzleDazzle 3c:37:86:15:aa:f9 -64 48 Y US WPA2(PSK/AES/AES) diff --git a/tests/fixtures/osx-10.14.6/file.json b/tests/fixtures/osx-10.14.6/file.json new file mode 100644 index 00000000..c7836537 --- /dev/null +++ b/tests/fixtures/osx-10.14.6/file.json @@ -0,0 +1 @@ +[{"filename": "Applications", "type": "directory"}, {"filename": "Desktop", "type": "directory"}, {"filename": "Documents", "type": "directory"}, {"filename": "Downloads", "type": "directory"}, {"filename": "Library", "type": "directory"}, {"filename": "Movies", "type": "directory"}, {"filename": "Music", "type": "directory"}, {"filename": "Pictures", "type": "directory"}, {"filename": "Postman", "type": "directory"}, {"filename": "Public", "type": "directory"}, {"filename": "Virtual Machines.localized", "type": "directory"}, {"filename": "another file with spaces", "type": "empty"}, {"filename": "ansible", "type": "directory"}, {"filename": "api", "type": "directory"}, {"filename": "argstest.py", "type": "Python script text executable, ASCII text"}, {"filename": "blkid-p.out", "type": "ASCII text"}, {"filename": "blkid-pi.out", "type": "ASCII text, with very long lines"}, {"filename": "blkid-ubuntu.out", "type": "ASCII text"}, {"filename": "blkid-udev-mult.out", "type": "ASCII text"}, {"filename": "blkid-udev.out", "type": "ASCII text"}, {"filename": "blkid.out", "type": "ASCII text"}, {"filename": "cd_catalog.xml", "type": "XML 1.0 document text, ASCII text, with CRLF line terminators"}, {"filename": "centosserial.sh", "type": "Bourne-Again shell script text executable, UTF-8 Unicode text"}, {"filename": "coreosserial.sh", "type": "Bourne-Again shell script text executable, UTF-8 Unicode text"}, {"filename": "fazserial.sh", "type": "Bourne-Again shell script text executable, UTF-8 Unicode text"}, {"filename": "fgt1serial.sh", "type": "Bourne-Again shell script text executable, UTF-8 Unicode text"}, {"filename": "fgt2serial.sh", "type": "Bourne-Again shell script text executable, UTF-8 Unicode text"}, {"filename": "file with spaces", "type": "empty"}, {"filename": "fortiweb-docker.sh", "type": "Bourne-Again shell script text executable, ASCII text"}, {"filename": "ftmgr.sh", "type": "Bourne-Again shell script text executable, ASCII text"}, {"filename": "git", "type": "directory"}, {"filename": "google-cloud-sdk", "type": "directory"}, {"filename": "ifconfiglines.json", "type": "ASCII text, with very long lines"}, {"filename": "jc-jq-jp-ps-cpu.gif", "type": "GIF image data, version 89a, 1572 x 1212"}, {"filename": "jc-jq-jp-uptime-small.gif", "type": "GIF image data, version 89a, 800 x 617"}, {"filename": "jc-jq-jp-uptime.gif", "type": "GIF image data, version 89a, 1572 x 1212"}, {"filename": "jp", "type": "Mach-O 64-bit executable x86_64"}, {"filename": "jp_1.1.12_osx_x86_64.zip", "type": "Zip archive data, at least v2.0 to extract"}, {"filename": "jupyter.sh", "type": "ASCII text"}, {"filename": "kb.sh", "type": "Bourne-Again shell script text executable, ASCII text"}, {"filename": "kbtesting.txt", "type": "ASCII text"}, {"filename": "kelly-aws.pem", "type": "PEM RSA private key"}, {"filename": "kellyargtest.py", "type": "Python script text executable, ASCII text"}, {"filename": "loadplot.sh", "type": "Bourne-Again shell script text executable, ASCII text"}, {"filename": "ls-R.out", "type": "UTF-8 Unicode text"}, {"filename": "ls-lR-empty-folder.out", "type": "ASCII text"}, {"filename": "ls-lR.out", "type": "UTF-8 Unicode text"}, {"filename": "myrecording", "type": "data"}, {"filename": "smcclient.jnlp", "type": "XML 1.0 document text, ASCII text"}, {"filename": "table.py", "type": "Python script text executable, ASCII text"}, {"filename": "test.ini", "type": "ASCII text"}, {"filename": "ubuntuserial.sh", "type": "Bourne-Again shell script text executable, UTF-8 Unicode text"}, {"filename": "utils", "type": "directory"}] diff --git a/tests/fixtures/osx-10.14.6/file.out b/tests/fixtures/osx-10.14.6/file.out new file mode 100644 index 00000000..7b3b78bb --- /dev/null +++ b/tests/fixtures/osx-10.14.6/file.out @@ -0,0 +1,53 @@ +Applications: directory +Desktop: directory +Documents: directory +Downloads: directory +Library: directory +Movies: directory +Music: directory +Pictures: directory +Postman: directory +Public: directory +Virtual Machines.localized: directory +another file with spaces: empty +ansible: directory +api: directory +argstest.py: Python script text executable, ASCII text +blkid-p.out: ASCII text +blkid-pi.out: ASCII text, with very long lines +blkid-ubuntu.out: ASCII text +blkid-udev-mult.out: ASCII text +blkid-udev.out: ASCII text +blkid.out: ASCII text +cd_catalog.xml: XML 1.0 document text, ASCII text, with CRLF line terminators +centosserial.sh: Bourne-Again shell script text executable, UTF-8 Unicode text +coreosserial.sh: Bourne-Again shell script text executable, UTF-8 Unicode text +fazserial.sh: Bourne-Again shell script text executable, UTF-8 Unicode text +fgt1serial.sh: Bourne-Again shell script text executable, UTF-8 Unicode text +fgt2serial.sh: Bourne-Again shell script text executable, UTF-8 Unicode text +file with spaces: empty +fortiweb-docker.sh: Bourne-Again shell script text executable, ASCII text +ftmgr.sh: Bourne-Again shell script text executable, ASCII text +git: directory +google-cloud-sdk: directory +ifconfiglines.json: ASCII text, with very long lines +jc-jq-jp-ps-cpu.gif: GIF image data, version 89a, 1572 x 1212 +jc-jq-jp-uptime-small.gif: GIF image data, version 89a, 800 x 617 +jc-jq-jp-uptime.gif: GIF image data, version 89a, 1572 x 1212 +jp: Mach-O 64-bit executable x86_64 +jp_1.1.12_osx_x86_64.zip: Zip archive data, at least v2.0 to extract +jupyter.sh: ASCII text +kb.sh: Bourne-Again shell script text executable, ASCII text +kbtesting.txt: ASCII text +kelly-aws.pem: PEM RSA private key +kellyargtest.py: Python script text executable, ASCII text +loadplot.sh: Bourne-Again shell script text executable, ASCII text +ls-R.out: UTF-8 Unicode text +ls-lR-empty-folder.out: ASCII text +ls-lR.out: UTF-8 Unicode text +myrecording: data +smcclient.jnlp: XML 1.0 document text, ASCII text +table.py: Python script text executable, ASCII text +test.ini: ASCII text +ubuntuserial.sh: Bourne-Again shell script text executable, UTF-8 Unicode text +utils: directory diff --git a/tests/fixtures/ubuntu-18.04/file.json b/tests/fixtures/ubuntu-18.04/file.json new file mode 100644 index 00000000..d4fc3678 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/file.json @@ -0,0 +1 @@ +[{"filename": "crayaml.yaml", "type": "ASCII text"}, {"filename": "git", "type": "directory"}, {"filename": "ifconfig-ubuntu.out", "type": "ASCII text"}, {"filename": "iptables-tests", "type": "directory"}, {"filename": "lastb.out", "type": "ASCII text"}, {"filename": "listjobs", "type": "ASCII text"}, {"filename": "ls-lR.out", "type": "ASCII text"}, {"filename": "ls-R.out", "type": "ASCII text"}, {"filename": "netstat-ae.out", "type": "ASCII text"}, {"filename": "netstat-aew.out", "type": "ASCII text"}, {"filename": "netstat-a.out", "type": "ASCII text"}, {"filename": "netstat-aw.out", "type": "ASCII text"}, {"filename": "resizeterm.sh", "type": "Bourne-Again shell script, ASCII text executable"}, {"filename": "snap", "type": "directory"}, {"filename": "ssout", "type": "ASCII text"}, {"filename": "sudofix", "type": "ASCII text"}, {"filename": "testfiles", "type": "directory"}, {"filename": "tmp", "type": "directory"}, {"filename": "trafficgen.sh", "type": "Bourne-Again shell script, ASCII text executable"}, {"filename": "xmltest.xml", "type": "XML 1.0 document, ASCII text"}] diff --git a/tests/fixtures/ubuntu-18.04/file.out b/tests/fixtures/ubuntu-18.04/file.out new file mode 100644 index 00000000..865b6cab --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/file.out @@ -0,0 +1,20 @@ +crayaml.yaml: ASCII text +git: directory +ifconfig-ubuntu.out: ASCII text +iptables-tests: directory +lastb.out: ASCII text +listjobs: ASCII text +ls-lR.out: ASCII text +ls-R.out: ASCII text +netstat-ae.out: ASCII text +netstat-aew.out: ASCII text +netstat-a.out: ASCII text +netstat-aw.out: ASCII text +resizeterm.sh: Bourne-Again shell script, ASCII text executable +snap: directory +ssout: ASCII text +sudofix: ASCII text +testfiles: directory +tmp: directory +trafficgen.sh: Bourne-Again shell script, ASCII text executable +xmltest.xml: XML 1.0 document, ASCII text diff --git a/tests/fixtures/ubuntu-18.04/ntpq-p.json b/tests/fixtures/ubuntu-18.04/ntpq-p.json new file mode 100644 index 00000000..5e1fb02c --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntpq-p.json @@ -0,0 +1 @@ +[{"state": null, "remote": "0.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "1.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "2.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "3.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "ntp.ubuntu.com", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": "+", "remote": "216.126.233.109", "refid": "128.227.205.3", "st": 2, "t": "u", "when": 24, "poll": 64, "reach": 1, "delay": 95.876, "offset": -65.426, "jitter": 4.502}, {"state": "+", "remote": "time.cloudflare", "refid": "10.4.0.197", "st": 3, "t": "u", "when": 33, "poll": 64, "reach": 1, "delay": 25.239, "offset": -69.809, "jitter": 3.313}, {"state": "+", "remote": "titan.crash-ove", "refid": "139.78.97.128", "st": 2, "t": "u", "when": 35, "poll": 64, "reach": 1, "delay": 60.008, "offset": -70.991, "jitter": 2.884}, {"state": "*", "remote": "clock.nyc.he.ne", "refid": ".CDMA.", "st": 1, "t": "u", "when": 31, "poll": 64, "reach": 1, "delay": 90.113, "offset": -65.938, "jitter": 4.621}, {"state": "-", "remote": "vf2.bbnx.net", "refid": "252.74.143.178", "st": 2, "t": "u", "when": 34, "poll": 64, "reach": 1, "delay": 209.667, "offset": -81.337, "jitter": 5.547}, {"state": "+", "remote": "t2.time.bf1.yah", "refid": "98.139.133.62", "st": 3, "t": "u", "when": 35, "poll": 64, "reach": 1, "delay": 104.541, "offset": -67.956, "jitter": 5.731}, {"state": null, "remote": "pugot.canonical", "refid": "17.253.34.125", "st": 2, "t": "u", "when": 43, "poll": 64, "reach": 1, "delay": 176.609, "offset": -65.874, "jitter": 0.0}, {"state": "-", "remote": "50-205-244-110-", "refid": "50.205.244.27", "st": 2, "t": "u", "when": 30, "poll": 64, "reach": 1, "delay": 76.322, "offset": -65.135, "jitter": 2.334}, {"state": "+", "remote": "1.time.dbsinet.", "refid": "146.186.222.14", "st": 2, "t": "u", "when": 31, "poll": 64, "reach": 1, "delay": 110.723, "offset": -65.056, "jitter": 6.198}, {"state": null, "remote": "golem.canonical", "refid": "17.253.34.123", "st": 2, "t": "u", "when": 40, "poll": 64, "reach": 1, "delay": 186.589, "offset": -61.769, "jitter": 0.0}, {"state": "-", "remote": "103.105.51.156", "refid": "206.55.191.142", "st": 2, "t": "u", "when": 30, "poll": 64, "reach": 1, "delay": 38.164, "offset": -65.286, "jitter": 6.412}, {"state": null, "remote": "alphyn.canonica", "refid": "17.253.108.125", "st": 2, "t": "u", "when": 44, "poll": 64, "reach": 1, "delay": 105.626, "offset": -63.73, "jitter": 0.0}, {"state": "-", "remote": "vf1.bbnx.net", "refid": "253.109.221.150", "st": 2, "t": "u", "when": 31, "poll": 64, "reach": 1, "delay": 101.941, "offset": -73.597, "jitter": 3.39}, {"state": null, "remote": "chilipepper.can", "refid": "145.238.203.14", "st": 2, "t": "u", "when": 40, "poll": 64, "reach": 1, "delay": 188.989, "offset": -59.352, "jitter": 0.0}] diff --git a/tests/fixtures/ubuntu-18.04/ntpq-p.out b/tests/fixtures/ubuntu-18.04/ntpq-p.out new file mode 100644 index 00000000..9125637f --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntpq-p.out @@ -0,0 +1,21 @@ + remote refid st t when poll reach delay offset jitter +============================================================================== + 0.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 1.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 2.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 3.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + ntp.ubuntu.com .POOL. 16 p - 64 0 0.000 0.000 0.000 ++216.126.233.109 128.227.205.3 2 u 24 64 1 95.876 -65.426 4.502 ++time.cloudflare 10.4.0.197 3 u 33 64 1 25.239 -69.809 3.313 ++titan.crash-ove 139.78.97.128 2 u 35 64 1 60.008 -70.991 2.884 +*clock.nyc.he.ne .CDMA. 1 u 31 64 1 90.113 -65.938 4.621 +-vf2.bbnx.net 252.74.143.178 2 u 34 64 1 209.667 -81.337 5.547 ++t2.time.bf1.yah 98.139.133.62 3 u 35 64 1 104.541 -67.956 5.731 + pugot.canonical 17.253.34.125 2 u 43 64 1 176.609 -65.874 0.000 +-50-205-244-110- 50.205.244.27 2 u 30 64 1 76.322 -65.135 2.334 ++1.time.dbsinet. 146.186.222.14 2 u 31 64 1 110.723 -65.056 6.198 + golem.canonical 17.253.34.123 2 u 40 64 1 186.589 -61.769 0.000 +-103.105.51.156 206.55.191.142 2 u 30 64 1 38.164 -65.286 6.412 + alphyn.canonica 17.253.108.125 2 u 44 64 1 105.626 -63.730 0.000 +-vf1.bbnx.net 253.109.221.150 2 u 31 64 1 101.941 -73.597 3.390 + chilipepper.can 145.238.203.14 2 u 40 64 1 188.989 -59.352 0.000 diff --git a/tests/fixtures/ubuntu-18.04/ntpq-p2.json b/tests/fixtures/ubuntu-18.04/ntpq-p2.json new file mode 100644 index 00000000..03ac3755 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntpq-p2.json @@ -0,0 +1 @@ +[{"remote": "0.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0, "state": null}, {"remote": "1.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0, "state": null}, {"remote": "2.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0, "state": null}, {"remote": "3.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0, "state": null}, {"remote": "ntp.ubuntu.com", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0, "state": null}, {"remote": "45.79.36.123_(t", "refid": "216.218.254.202", "st": 2, "t": "u", "when": 11, "poll": 64, "reach": 7, "delay": 68.172, "offset": 4.404, "jitter": 4.878, "state": "+"}, {"remote": "199.188.64.12_(", "refid": "173.161.33.165", "st": 2, "t": "u", "when": 9, "poll": 64, "reach": 7, "delay": 78.823, "offset": 2.148, "jitter": 8.739, "state": "+"}, {"remote": "ntp2.wiktel.com", "refid": ".GPS.", "st": 1, "t": "u", "when": 25, "poll": 64, "reach": 7, "delay": 76.857, "offset": 0.473, "jitter": 7.89, "state": "*"}, {"remote": "atl0.jane.mattn", "refid": "35.73.197.144", "st": 2, "t": "u", "when": 32, "poll": 64, "reach": 7, "delay": 87.536, "offset": 8.641, "jitter": 4.544, "state": "#"}, {"remote": "x.ns.gin.ntt.ne", "refid": "249.224.99.213", "st": 2, "t": "u", "when": 28, "poll": 64, "reach": 7, "delay": 25.021, "offset": 3.361, "jitter": 7.793, "state": "+"}, {"remote": "srcf-ntp.stanfo", "refid": "171.64.7.105", "st": 2, "t": "u", "when": 26, "poll": 64, "reach": 7, "delay": 28.053, "offset": 7.253, "jitter": 4.524, "state": "-"}, {"remote": "linode.ibendit.", "refid": "64.250.105.227", "st": 2, "t": "u", "when": 28, "poll": 64, "reach": 7, "delay": 56.841, "offset": -0.305, "jitter": 8.279, "state": "#"}, {"remote": "71.66.197.233", "refid": ".GPS.", "st": 1, "t": "u", "when": 26, "poll": 64, "reach": 7, "delay": 127.766, "offset": -0.769, "jitter": 3.465, "state": "+"}, {"remote": "time.aja.com", "refid": "198.169.208.144", "st": 2, "t": "u", "when": 32, "poll": 64, "reach": 7, "delay": 39.673, "offset": 4.684, "jitter": 4.916, "state": "+"}, {"remote": "23.152.160.126", "refid": "84.168.88.243", "st": 2, "t": "u", "when": 28, "poll": 64, "reach": 7, "delay": 21.553, "offset": 3.245, "jitter": 8.612, "state": "+"}, {"remote": "ntp.backplanedn", "refid": "152.2.133.52", "st": 2, "t": "u", "when": 30, "poll": 64, "reach": 7, "delay": 93.009, "offset": 9.337, "jitter": 10.03, "state": "#"}, {"remote": "chilipepper.can", "refid": "193.79.237.14", "st": 2, "t": "u", "when": 32, "poll": 64, "reach": 7, "delay": 165.084, "offset": 5.872, "jitter": 3.797, "state": null}, {"remote": "198.255.68.106", "refid": "192.168.1.193", "st": 2, "t": "u", "when": 26, "poll": 64, "reach": 7, "delay": 30.911, "offset": 3.034, "jitter": 8.201, "state": "+"}, {"remote": "golem.canonical", "refid": "17.253.34.251", "st": 2, "t": "u", "when": 28, "poll": 64, "reach": 7, "delay": 156.657, "offset": 3.767, "jitter": 5.448, "state": null}, {"remote": "vps.jan-jaap.ne", "refid": "132.163.96.1", "st": 2, "t": "u", "when": 23, "poll": 64, "reach": 7, "delay": 184.394, "offset": -7.118, "jitter": 4.585, "state": "#"}, {"remote": "vf2.bbnx.net", "refid": "252.74.143.178", "st": 2, "t": "u", "when": 28, "poll": 64, "reach": 7, "delay": 97.275, "offset": 0.824, "jitter": 18.08, "state": "+"}, {"remote": "pugot.canonical", "refid": "17.253.34.253", "st": 2, "t": "u", "when": 29, "poll": 64, "reach": 7, "delay": 157.069, "offset": 3.709, "jitter": 8.753, "state": null}] diff --git a/tests/fixtures/ubuntu-18.04/ntpq-p2.out b/tests/fixtures/ubuntu-18.04/ntpq-p2.out new file mode 100644 index 00000000..a2bd4033 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntpq-p2.out @@ -0,0 +1,24 @@ + remote refid st t when poll reach delay offset jitter +============================================================================== + 0.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 1.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 2.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 3.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + ntp.ubuntu.com .POOL. 16 p - 64 0 0.000 0.000 0.000 ++45.79.36.123 (t 216.218.254.202 2 u 11 64 7 68.172 4.404 4.878 ++199.188.64.12 ( 173.161.33.165 2 u 9 64 7 78.823 2.148 8.739 +*ntp2.wiktel.com .GPS. 1 u 25 64 7 76.857 0.473 7.890 +#atl0.jane.mattn 35.73.197.144 2 u 32 64 7 87.536 8.641 4.544 ++x.ns.gin.ntt.ne 249.224.99.213 2 u 28 64 7 25.021 3.361 7.793 +-srcf-ntp.stanfo 171.64.7.105 2 u 26 64 7 28.053 7.253 4.524 +#linode.ibendit. 64.250.105.227 2 u 28 64 7 56.841 -0.305 8.279 ++71.66.197.233 .GPS. 1 u 26 64 7 127.766 -0.769 3.465 ++time.aja.com 198.169.208.144 2 u 32 64 7 39.673 4.684 4.916 ++23.152.160.126 84.168.88.243 2 u 28 64 7 21.553 3.245 8.612 +#ntp.backplanedn 152.2.133.52 2 u 30 64 7 93.009 9.337 10.030 + chilipepper.can 193.79.237.14 2 u 32 64 7 165.084 5.872 3.797 ++198.255.68.106 192.168.1.193 2 u 26 64 7 30.911 3.034 8.201 + golem.canonical 17.253.34.251 2 u 28 64 7 156.657 3.767 5.448 +#vps.jan-jaap.ne 132.163.96.1 2 u 23 64 7 184.394 -7.118 4.585 ++vf2.bbnx.net 252.74.143.178 2 u 28 64 7 97.275 0.824 18.080 + pugot.canonical 17.253.34.253 2 u 29 64 7 157.069 3.709 8.753 diff --git a/tests/fixtures/ubuntu-18.04/ntpq-pn.json b/tests/fixtures/ubuntu-18.04/ntpq-pn.json new file mode 100644 index 00000000..24224484 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntpq-pn.json @@ -0,0 +1 @@ +[{"state": null, "remote": "0.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "1.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "2.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "3.ubuntu.pool.n", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": null, "remote": "ntp.ubuntu.com", "refid": ".POOL.", "st": 16, "t": "p", "when": null, "poll": 64, "reach": 0, "delay": 0.0, "offset": 0.0, "jitter": 0.0}, {"state": "+", "remote": "216.126.233.109", "refid": "128.227.205.3", "st": 2, "t": "u", "when": 40, "poll": 64, "reach": 1, "delay": 95.876, "offset": -65.426, "jitter": 4.502}, {"state": "+", "remote": "162.159.200.123", "refid": "10.4.0.197", "st": 3, "t": "u", "when": 39, "poll": 64, "reach": 1, "delay": 25.239, "offset": -69.809, "jitter": 3.313}, {"state": "+", "remote": "47.190.36.235", "refid": "139.78.97.128", "st": 2, "t": "u", "when": 41, "poll": 64, "reach": 1, "delay": 60.008, "offset": -70.991, "jitter": 2.884}, {"state": "*", "remote": "209.51.161.238", "refid": ".CDMA.", "st": 1, "t": "u", "when": 37, "poll": 64, "reach": 1, "delay": 90.113, "offset": -65.938, "jitter": 4.621}, {"state": "-", "remote": "23.31.21.164", "refid": "252.74.143.178", "st": 2, "t": "u", "when": 40, "poll": 64, "reach": 1, "delay": 209.667, "offset": -81.337, "jitter": 5.547}, {"state": "+", "remote": "72.30.35.88", "refid": "98.139.133.62", "st": 3, "t": "u", "when": 40, "poll": 64, "reach": 1, "delay": 104.541, "offset": -67.956, "jitter": 5.731}, {"state": null, "remote": "91.189.94.4", "refid": "17.253.34.125", "st": 2, "t": "u", "when": 48, "poll": 64, "reach": 1, "delay": 176.609, "offset": -65.874, "jitter": 0.0}, {"state": "-", "remote": "50.205.244.110", "refid": "50.205.244.27", "st": 2, "t": "u", "when": 35, "poll": 64, "reach": 1, "delay": 76.322, "offset": -65.135, "jitter": 2.334}, {"state": "+", "remote": "199.223.248.99", "refid": "146.186.222.14", "st": 2, "t": "u", "when": 36, "poll": 64, "reach": 1, "delay": 110.723, "offset": -65.056, "jitter": 6.198}, {"state": null, "remote": "91.189.89.199", "refid": "17.253.34.123", "st": 2, "t": "u", "when": 45, "poll": 64, "reach": 1, "delay": 186.589, "offset": -61.769, "jitter": 0.0}, {"state": "-", "remote": "103.105.51.156", "refid": "206.55.191.142", "st": 2, "t": "u", "when": 34, "poll": 64, "reach": 1, "delay": 38.164, "offset": -65.286, "jitter": 6.412}, {"state": null, "remote": "91.189.91.157", "refid": "17.253.108.125", "st": 2, "t": "u", "when": 48, "poll": 64, "reach": 1, "delay": 105.626, "offset": -63.73, "jitter": 0.0}, {"state": "-", "remote": "23.31.21.163", "refid": "253.109.221.150", "st": 2, "t": "u", "when": 35, "poll": 64, "reach": 1, "delay": 101.941, "offset": -73.597, "jitter": 3.39}, {"state": null, "remote": "91.189.89.198", "refid": "145.238.203.14", "st": 2, "t": "u", "when": 44, "poll": 64, "reach": 1, "delay": 188.989, "offset": -59.352, "jitter": 0.0}] diff --git a/tests/fixtures/ubuntu-18.04/ntpq-pn.out b/tests/fixtures/ubuntu-18.04/ntpq-pn.out new file mode 100644 index 00000000..f9fe62e7 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntpq-pn.out @@ -0,0 +1,21 @@ + remote refid st t when poll reach delay offset jitter +============================================================================== + 0.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 1.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 2.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 3.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + ntp.ubuntu.com .POOL. 16 p - 64 0 0.000 0.000 0.000 ++216.126.233.109 128.227.205.3 2 u 40 64 1 95.876 -65.426 4.502 ++162.159.200.123 10.4.0.197 3 u 39 64 1 25.239 -69.809 3.313 ++47.190.36.235 139.78.97.128 2 u 41 64 1 60.008 -70.991 2.884 +*209.51.161.238 .CDMA. 1 u 37 64 1 90.113 -65.938 4.621 +-23.31.21.164 252.74.143.178 2 u 40 64 1 209.667 -81.337 5.547 ++72.30.35.88 98.139.133.62 3 u 40 64 1 104.541 -67.956 5.731 + 91.189.94.4 17.253.34.125 2 u 48 64 1 176.609 -65.874 0.000 +-50.205.244.110 50.205.244.27 2 u 35 64 1 76.322 -65.135 2.334 ++199.223.248.99 146.186.222.14 2 u 36 64 1 110.723 -65.056 6.198 + 91.189.89.199 17.253.34.123 2 u 45 64 1 186.589 -61.769 0.000 +-103.105.51.156 206.55.191.142 2 u 34 64 1 38.164 -65.286 6.412 + 91.189.91.157 17.253.108.125 2 u 48 64 1 105.626 -63.730 0.000 +-23.31.21.163 253.109.221.150 2 u 35 64 1 101.941 -73.597 3.390 + 91.189.89.198 145.238.203.14 2 u 44 64 1 188.989 -59.352 0.000 diff --git a/tests/fixtures/ubuntu-18.04/ntqp-p.out b/tests/fixtures/ubuntu-18.04/ntqp-p.out new file mode 100644 index 00000000..9125637f --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/ntqp-p.out @@ -0,0 +1,21 @@ + remote refid st t when poll reach delay offset jitter +============================================================================== + 0.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 1.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 2.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + 3.ubuntu.pool.n .POOL. 16 p - 64 0 0.000 0.000 0.000 + ntp.ubuntu.com .POOL. 16 p - 64 0 0.000 0.000 0.000 ++216.126.233.109 128.227.205.3 2 u 24 64 1 95.876 -65.426 4.502 ++time.cloudflare 10.4.0.197 3 u 33 64 1 25.239 -69.809 3.313 ++titan.crash-ove 139.78.97.128 2 u 35 64 1 60.008 -70.991 2.884 +*clock.nyc.he.ne .CDMA. 1 u 31 64 1 90.113 -65.938 4.621 +-vf2.bbnx.net 252.74.143.178 2 u 34 64 1 209.667 -81.337 5.547 ++t2.time.bf1.yah 98.139.133.62 3 u 35 64 1 104.541 -67.956 5.731 + pugot.canonical 17.253.34.125 2 u 43 64 1 176.609 -65.874 0.000 +-50-205-244-110- 50.205.244.27 2 u 30 64 1 76.322 -65.135 2.334 ++1.time.dbsinet. 146.186.222.14 2 u 31 64 1 110.723 -65.056 6.198 + golem.canonical 17.253.34.123 2 u 40 64 1 186.589 -61.769 0.000 +-103.105.51.156 206.55.191.142 2 u 30 64 1 38.164 -65.286 6.412 + alphyn.canonica 17.253.108.125 2 u 44 64 1 105.626 -63.730 0.000 +-vf1.bbnx.net 253.109.221.150 2 u 31 64 1 101.941 -73.597 3.390 + chilipepper.can 145.238.203.14 2 u 40 64 1 188.989 -59.352 0.000 diff --git a/tests/fixtures/ubuntu-18.04/timedatectl.json b/tests/fixtures/ubuntu-18.04/timedatectl.json new file mode 100644 index 00000000..4cc48998 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/timedatectl.json @@ -0,0 +1 @@ +{"local_time": "Wed 2020-03-11 00:51:11 UTC", "universal_time": "Wed 2020-03-11 00:51:11 UTC", "rtc_time": "Wed 2020-03-11 00:51:11", "time_zone": "Etc/UTC (UTC, +0000)", "system_clock_synchronized": true, "systemd-timesyncd.service_active": true, "rtc_in_local_tz": false} diff --git a/tests/fixtures/ubuntu-18.04/timedatectl.out b/tests/fixtures/ubuntu-18.04/timedatectl.out new file mode 100644 index 00000000..38f9a472 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/timedatectl.out @@ -0,0 +1,7 @@ + Local time: Wed 2020-03-11 00:51:11 UTC + Universal time: Wed 2020-03-11 00:51:11 UTC + RTC time: Wed 2020-03-11 00:51:11 + Time zone: Etc/UTC (UTC, +0000) + System clock synchronized: yes +systemd-timesyncd.service active: yes + RTC in local TZ: no diff --git a/tests/test_airport.py b/tests/test_airport.py new file mode 100644 index 00000000..91907515 --- /dev/null +++ b/tests/test_airport.py @@ -0,0 +1,28 @@ +import os +import unittest +import json +import jc.parsers.airport + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + + def setUp(self): + # input + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/airport-I.out'), 'r', encoding='utf-8') as f: + self.osx_10_14_6_airport_I = f.read() + + # output + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/airport-I.json'), 'r', encoding='utf-8') as f: + self.osx_10_14_6_airport_I_json = json.loads(f.read()) + + def test_airport_I_osx_10_14_6(self): + """ + Test 'airport -I' on OSX 10.14.6 + """ + self.assertEqual(jc.parsers.airport.parse(self.osx_10_14_6_airport_I, quiet=True), self.osx_10_14_6_airport_I_json) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_airport_s.py b/tests/test_airport_s.py new file mode 100644 index 00000000..2b964f01 --- /dev/null +++ b/tests/test_airport_s.py @@ -0,0 +1,28 @@ +import os +import unittest +import json +import jc.parsers.airport_s + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + + def setUp(self): + # input + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/airport-s.out'), 'r', encoding='utf-8') as f: + self.osx_10_14_6_airport_s = f.read() + + # output + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/airport-s.json'), 'r', encoding='utf-8') as f: + self.osx_10_14_6_airport_s_json = json.loads(f.read()) + + def test_airport_s_osx_10_14_6(self): + """ + Test 'airport -s' on OSX 10.14.6 + """ + self.assertEqual(jc.parsers.airport_s.parse(self.osx_10_14_6_airport_s, quiet=True), self.osx_10_14_6_airport_s_json) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_cli.py b/tests/test_cli.py index fdd768da..d1a3a7d8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -13,6 +13,9 @@ class MyTests(unittest.TestCase): 'jc -p pip3 show jc': 'pip3 show jc | jc --pip-show -p', 'jc -prd last': 'last | jc --last -prd', 'jc -prd lastb': 'lastb | jc --last -prd', + 'jc -p airport -I': 'airport -I | jc --airport -p', + 'jc -p -r airport -I': 'airport -I | jc --airport -pr', + 'jc -prd airport -I': 'airport -I | jc --airport -prd', 'jc -p nonexistent command': 'nonexistent command', 'jc -ap': None } diff --git a/tests/test_file.py b/tests/test_file.py new file mode 100644 index 00000000..67181854 --- /dev/null +++ b/tests/test_file.py @@ -0,0 +1,52 @@ +import os +import unittest +import json +import jc.parsers.file + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + + def setUp(self): + # input + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/file.out'), 'r', encoding='utf-8') as f: + self.centos_7_7_file = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/file.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_file = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/file.out'), 'r', encoding='utf-8') as f: + self.osx_10_14_6_file = f.read() + + # output + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/file.json'), 'r', encoding='utf-8') as f: + self.centos_7_7_file_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/file.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_file_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/file.json'), 'r', encoding='utf-8') as f: + self.osx_10_14_6_file_json = json.loads(f.read()) + + def test_file_centos_7_7(self): + """ + Test 'file *' on Centos 7.7 + """ + self.assertEqual(jc.parsers.file.parse(self.centos_7_7_file, quiet=True), self.centos_7_7_file_json) + + def test_file_ubuntu_18_4(self): + """ + Test 'file *' on Ubuntu 18.4 + """ + self.assertEqual(jc.parsers.file.parse(self.ubuntu_18_4_file, quiet=True), self.ubuntu_18_4_file_json) + + def test_file_osx_10_14_6(self): + """ + Test 'file *' on OSX 10.14.6 + """ + self.assertEqual(jc.parsers.file.parse(self.osx_10_14_6_file, quiet=True), self.osx_10_14_6_file_json) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_ntpq.py b/tests/test_ntpq.py new file mode 100644 index 00000000..b9c2f23a --- /dev/null +++ b/tests/test_ntpq.py @@ -0,0 +1,76 @@ +import os +import unittest +import json +import jc.parsers.ntpq + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + + def setUp(self): + # input + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/ntpq-p.out'), 'r', encoding='utf-8') as f: + self.centos_7_7_ntpq_p = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/ntpq-p.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_ntpq_p = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/ntpq-pn.out'), 'r', encoding='utf-8') as f: + self.centos_7_7_ntpq_pn = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/ntpq-pn.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_ntpq_pn = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/ntpq-p2.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_ntpq_p2 = f.read() + + # output + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/ntpq-p.json'), 'r', encoding='utf-8') as f: + self.centos_7_7_ntpq_p_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/ntpq-p.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_ntpq_p_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/ntpq-pn.json'), 'r', encoding='utf-8') as f: + self.centos_7_7_ntpq_pn_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/ntpq-pn.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_ntpq_pn_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/ntpq-p2.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_ntpq_p2_json = json.loads(f.read()) + + def test_ntpq_p_centos_7_7(self): + """ + Test 'ntpq -p' on Centos 7.7 + """ + self.assertEqual(jc.parsers.ntpq.parse(self.centos_7_7_ntpq_p, quiet=True), self.centos_7_7_ntpq_p_json) + + def test_ntpq_p_ubuntu_18_4(self): + """ + Test 'ntpq -p' on Ubuntu 18.4 + """ + self.assertEqual(jc.parsers.ntpq.parse(self.ubuntu_18_4_ntpq_p, quiet=True), self.ubuntu_18_4_ntpq_p_json) + + def test_ntpq_pn_centos_7_7(self): + """ + Test 'ntpq -pn' on Centos 7.7 + """ + self.assertEqual(jc.parsers.ntpq.parse(self.centos_7_7_ntpq_pn, quiet=True), self.centos_7_7_ntpq_pn_json) + + def test_ntpq_pn_ubuntu_18_4(self): + """ + Test 'ntpq -pn' on Ubuntu 18.4 + """ + self.assertEqual(jc.parsers.ntpq.parse(self.ubuntu_18_4_ntpq_pn, quiet=True), self.ubuntu_18_4_ntpq_pn_json) + + def test_ntpq_p2_ubuntu_18_4(self): + """ + Test 'ntpq -p' with ip data with spaces on Ubuntu 18.4 + """ + self.assertEqual(jc.parsers.ntpq.parse(self.ubuntu_18_4_ntpq_p2, quiet=True), self.ubuntu_18_4_ntpq_p2_json) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_timedatectl.py b/tests/test_timedatectl.py new file mode 100644 index 00000000..52e086e2 --- /dev/null +++ b/tests/test_timedatectl.py @@ -0,0 +1,40 @@ +import os +import unittest +import json +import jc.parsers.timedatectl + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + + def setUp(self): + # input + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/timedatectl.out'), 'r', encoding='utf-8') as f: + self.centos_7_7_timedatectl = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/timedatectl.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_timedatectl = f.read() + + # output + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/timedatectl.json'), 'r', encoding='utf-8') as f: + self.centos_7_7_timedatectl_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/timedatectl.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_timedatectl_json = json.loads(f.read()) + + def test_timedatectl_centos_7_7(self): + """ + Test 'timedatectl' on Centos 7.7 + """ + self.assertEqual(jc.parsers.timedatectl.parse(self.centos_7_7_timedatectl, quiet=True), self.centos_7_7_timedatectl_json) + + def test_timedatectl_ubuntu_18_4(self): + """ + Test 'timedatectl' on Ubuntu 18.4 + """ + self.assertEqual(jc.parsers.timedatectl.parse(self.ubuntu_18_4_timedatectl, quiet=True), self.ubuntu_18_4_timedatectl_json) + + +if __name__ == '__main__': + unittest.main()