#!/usr/bin/ruby

# = Stella
# 
# === Your friend in web app performance testing
#
# Config (default paths):
# 
#     ./.stella/config   (current directory)
#     ~/.stella/config   (your home directory)
#
# Usage:
# 
#     $ stella -h
#     $ stella verify -p plans/basic.rb http://test.example.com/
#     $ stella generate -u 10 -t 60 http://test.example.com/
#     $ stella generate -u 10 -r 40 -p plans/basic.rb http://test.example.com/
#
#--

# Put our local lib in first place
BASE_PATH = File.expand_path File.join(File.dirname(__FILE__), '..')
lib_dir = File.join(BASE_PATH, 'lib')
$:.unshift lib_dir  

require 'drydock'
require 'stella'
require 'stella/cli'

# Command-line interface for bin/stella
class Stella::CLI::Definition
  extend Drydock
  
  debug :off
  
  # ----------------------------------------  STELLA GLOBALS  --------
  # ------------------------------------------------------------------
  
  #global :A, :apikey, String, "API Key"
  #global :S, :secret, String, "Secret Key"
  global :D, :debug, "Enable debug mode" do
    Drydock.debug true
    Stella.enable_debug
  end
  global :W, :wait, Integer, "Seconds to wait before starting test"
  global :H, :withheader, "Include X-Stella-ID request header" 
  global :P, :withparam, "Include __stella query parameter header"
  global :o, :output, String, "Write output to the given file" do |v|
    String.disable_color
    Stella.log.output = v
  end
  global :var, Array, 'Set an arbitrary variable (--var "name=v")'
  global :f, :format, String, "Output format (partial support)"
  global :n, :nocolor, "Disable output colors" do
    String.disable_color
  end
  global :q, :quiet, "Be quiet!" do
    Stella.enable_quiet
  end
  global :v, :verbose, "Increase verbosity of output (e.g. -v or -vv or -vvv)" do
    Stella.stdout.lev += 1
  end
  global :nostats, "Disable stat collection" do
    true
  end
  global :notemplates, "Disable template parsing" do
    true
  end
  global :V, :version, "Display version number" do
    puts "Stella version: #{Stella::VERSION.inspect}"
    exit 0
  end

  
  # ------------------------------------------------  STELLA  --------
  # ------------------------------------------------------------------
  about "Instructions for running the example app and test"
  usage "stella example"
  command :example => Stella::CLI
  
  about "View Stella configuration"
  usage "stella config"
  command :config => Stella::CLI
  
  about "Preview a test plan"
  usage "stella preview [-p path/2/testplan.rb] "
  option :c, :clients, Integer, "Maximum number of virtual clients (ignored)"
  option :a, :arrival, Float, "Arrival rate (ignored)"
  option :r, :repetitions, Integer, "Number of times to repeat the testplan (ignored)"
  option :d, :duration, String, "Max duration to run test (ignored)"
  option :W, :nowait, "Ignore wait times (ignored)"
  option :w, :wait, Float, "Wait time (in seconds) between client requests (ignored if testplan supplied)"
  option :p, :testplan, String, "Path to testplan" 
  option :g, :granularity, Integer, "Amount of time (in seconds) between timeline rotations"
  command :preview => Stella::CLI
  
  about "Verify a test plan"
  usage "stella verify [-p path/2/testplan.rb] URI"
  usage "e.g."
  usage "   $ stella verify -p path/2/testplan.rb http://stellaaahhhh.com/"
  option :c, :clients, Integer, "Maximum number of virtual clients (ignored)"
  option :a, :arrival, Float, "Arrival rate (ignored)"
  option :r, :repetitions, Integer, "Number of times to repeat the testplan (ignored)"
  option :d, :duration, String, "Max duration to run test (ignored)"
  option :W, :nowait, "Ignore wait times"
  option :w, :wait, Float, "Wait time (in seconds) between client requests (ignored if testplan supplied)"
  option :p, :testplan, String, "Path to testplan" 
  option :g, :granularity, Integer, "Amount of time (in seconds) between timeline rotations"
  command :verify => Stella::CLI
  
  about "Generate requests"
  usage "stella generate [options] URI"
  #usage "stella load [options] URI"
  #usage "stella stress [options] URI"
  usage "e.g. "
  usage "   $ stella generate -p path/2/testplan.rb -u 100 -r 50 http://stellaaahhhh.com:3114/"
  #usage "   $ stella stress --clients=50 --repetitions=20 http://stellaaahhhh.com/"
  option :c, :clients, Integer, "Maximum number of virtual clients"
  option :a, :arrival, Float, "Arrival rate (new clients per second)"
  option :r, :repetitions, Integer, "Number of times to repeat the testplan (per vclient)"
  option :d, :duration, String, "Max duration to run test"
  option :W, :nowait, "Ignore wait times"
  option :w, :wait, Float, "Wait time (in seconds) between client requests (ignored if testplan supplied)"
  option :p, :testplan, String, "Path to testplan" 
  option :g, :granularity, Integer, "Amount of time (in seconds) between timeline rotations"
  command :generate => Stella::CLI
  
  about "Initialize Stella configuration"
  command :init do
    Stella::Config.init
  end
  
  if Drydock.debug?
    about "Blast away all Stella config assets"
    command :blast do
      Stella::Config.blast
    end
  end
  
  
  # ----------------------------------  STELLA MISCELLANEOUS  --------
  # ------------------------------------------------------------------
  before do |obj|
    #puts $$
    @start = Time.now
    if obj.global.pause
      obj.global.pause.to_i.times do |i|
        print "Waiting for %s" % [(obj.global.pause-i)]
        sleep 1
        print "\r%30s\r" % ''  # clear line
      end
    end
  end

  after do |obj|  
    @elapsed = Time.now - @start
    if @elapsed > 0.1
      Stella.stdout.puts 2, "#{$/}Elapsed: %.2f seconds" % @elapsed.to_f
    end
    code = obj.exit_code if obj.respond_to? :exit_code
    exit code ||= 0
  end
  
end

begin
  Drydock.run!(ARGV, STDIN) if Drydock.run? && !Drydock.has_run?
rescue Drydock::ArgError, Drydock::OptError => ex
  STDERR.puts ex.message
  STDERR.puts ex.usage
rescue Drydock::InvalidArgument => ex
  STDERR.puts ex.message
rescue Drydock::UnknownCommand => ex
  STDERR.puts "Unknown command: %s" % ex.name
rescue Stella::Error => ex
  STDERR.puts ex.message
  STDERR.puts ex.backtrace if Stella.stdout.lev > 2 || Stella.debug?
rescue Interrupt
  puts $/, "Exiting... "
  exit 1
rescue => ex
  STDERR.puts "ERROR (#{ex.class.to_s}): #{ex.message}"
  STDERR.puts ex.backtrace if Stella.stdout.lev > 2 || Stella.debug?
end