Thursday, October 16, 2014

Unit Testing Bash Scripts

Although I have written a lot of shell scripts the past year, I did not write a single unit test to verify my code. In Python, I have unittest module. In Java, I have JUnit for that... it seems I don't have any tool for bash scripts. Inspired by haridsv in http://stackoverflow.com/questions/971945/unit-testing-for-shell-scripts, I have achieved something that looks quite promising without installing extra lib, but repeating few lines... Task: Run a test.sh script to change the content of the /etc/ssh/sshd_config How can we test this script? We put everything into functions and test the functions! We are going to put the functions into a file with the same name + "_functions" The last declare, grep and while statement will automatically run every functions starting with "test_". You will get the line number too if it fails. You can also put setUp() or tearDown() feature into the while loop before/after the eval. To run this test, just run ./test_functions.sh Hope that helps. *EDIT: add ERROR or the eval will return 0 even it failed the middle tests.

Friday, September 19, 2014

Integrate jkeymaster with javAuto to support HotKey

Today I was looking for an alternative of AutoIt for Linux and found javAuto. After few mins, I already missed the HotKey function in AutoIt, and it seems javAuto has no support for this. A simple search of "Java Hotkey" returned https://github.com/tulskiy/jkeymaster, and actually it's easy to combine these two tools. Download the jkeymaster, build it with maven. You will find two jar files: jkeymaster-1.2-SNAPSHOT.jar and jna-4.1.0.jar in the target folder. Copy these two jars to the working directory along with javAuto.jar. For the Test.java, using F11 as the hotkey!

Wednesday, February 12, 2014

Node.js spawn command line in Linux

This is just a wrapper of the Node.js spawn in Linux containing Bash. A trick is to use /bin/bash for the child process and just pipe the command there.
run = (cmd, arg1, arg2) ->
  throw new Error 'The last argument needs to be a fn.' \
      if arg2? and typeof arg2 isnt 'function' or \
      !arg2? and typeof arg1 isnt 'function'

  options =
    'quiet': false

  if typeof arg1 is 'object'
    options[k] = v for k, v of arg1

  terminal = require('child_process').spawn('bash');

  stdout = ''
  terminal.stdout.on 'data', (data) ->
    stdout += data.toString()
    process.stdout.write data.toString() unless options['quiet']

  stderr = ''
  terminal.stderr.on 'data', (data) ->
    stderr += data.toString()
    process.stderr.write data.toString() unless options['quiet']

  terminal.on 'close', (code) ->
    stdout = stdout.replace(/^\s+|\s+$/g, '')
    stdout = if stdout.length > 0 then stdout.split '\n' else []
    stderr = stderr.replace(/^\s+|\s+$/g, '')
    stderr = if stderr.length > 0 then stderr.split '\n' else []

    callback = if typeof arg1 is 'function' then arg1 else arg2
    if code == 0
      callback null, stdout, stderr
    else
      callback new Error("#{cmd} exited with code #{code}."), stdout, stderr

  console.log "+ #{cmd} (#{new Date()})" unless options['quiet']
  terminal.stdin.write cmd
  terminal.stdin.end()

run 'ls -al *.coffee', (err, stdout, stderr) ->
  console.log err
  console.log stdout
  console.log stderr

Thursday, January 30, 2014

awk sub, system, and getline to variable example

This is an example of having awk with system and getline calls... This is similar what debsums -c is doing but you can actually supply a custom md5sum list...
while read line; do echo $line | awk '{ x=$1; $1=""; sub("^ ", "/", $0); z=$0; sub("^", "\"", $0); sub("$", "\"", $0); if (system("[ -f " $0 " ]") == 0) { cmd="md5sum " $0 " | cut -d\  -f1"; cmd | getline y; close(cmd); if (y != x) printf "%-73s FAILED\n", z; } else printf "%-71s NOTFOUND\n", z;}'; done < /var/lib/dpkg/info/libc-bin.md5sums