#!/usr/bin/env python

# GStreamer QA system
#
#       gst-media-test
#
# Copyright (c) 2007, Edward Hervey <bilboed@bilboed.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

"""
Attempts to simulate the behaviour of the (now deprecated) gst-media-test
"""

# TODO
#
# Create a scenario from the given inputs
#
# Find similarities with other CLI client and move those up in a
# CLI base class.

import sys
import string
import time
import os.path
from optparse import OptionParser
from insanity.client import CommandLineTesterClient
from insanity.scenario import Scenario
from insanity.generators.filesystem import URIFileSystemGenerator
from insanity.generators.playlist import PlaylistGenerator
from insanity.monitor import GstDebugLogMonitor, ValgrindMemCheckMonitor, GDBMonitor
from insanity.testrun import TestRun
import insanity.utils as utils
from tests.scenarios.gstmediatest import GstMediaTestScenario

class GstMediaTestClient(CommandLineTesterClient):

    __software_name__ = """gst-media-test"""
    # simulate the behaviour of the previous gst-media-test
    #
    # Here we only run for one TestRun and then exit
    #
    # Some options might be difficult to reproduce with the new system.

    def __init__(self, testrun, verbose=False, usemysql=False):
        CommandLineTesterClient.__init__(self, verbose=verbose, singlerun=True)
        if usemysql:
            from insanity.storage.mysql import MySQLStorage
            self.setStorage(MySQLStorage())
        self.addTestRun(testrun)

def create_testrun(files=[], testscripts=[], recursive=True, topdir=None,
                   extreme=False, valgrinding=False,
                   debuglevel=2, debuglevel2=5,
                   acceptlist=[], rejectlist=[],
                   maxnbtests=2, rerun=True,
                   playlist=None):
    """
    Takes the parameters of gst-media-test and creates a TestRun object
    """
    # the testrun will just be a normal list
    # Each test will be a Scenario that will rerun the test with more
    # aggressive settings
    # Use generator for the arguments
    # TODO : port existing gst-media-test tests to new classes

    # FileSystemGenerator from the following arguments:
    # * files
    # * recursive
    # * acceptlist
    # * rejectlist
    if not files == []:
        generator1 = URIFileSystemGenerator(paths=files, recursive=recursive,
                                            matching=acceptlist,
                                            reject=rejectlist)
    elif playlist:
        generator1 = PlaylistGenerator(location=playlist)
    else:
        generator1 = None

    # get the classes corresponding to the given tests
    tests = [utils.get_test_class(name) for name in testscripts]

    # our monitors
    gdbscriptfile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gdb.instructions")
    monitors = [(GDBMonitor, {"gdb-script" : gdbscriptfile})]
    if valgrinding:
        # get full location of gst.supp
        suppfile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gst.supp")
        monitors.append((ValgrindMemCheckMonitor,
                         {"suppression-files":suppfile}))
    if not rerun:
        monitors.append((GstDebugLogMonitor, {"debug-level":str(debuglevel)}))

    # get the full path for topdir
    if topdir:
        topdir = os.path.abspath(topdir)
    testrun = TestRun(maxnbtests=maxnbtests, workingdir=topdir)
    for test in tests:
        if rerun:
            testrun.addTest(GstMediaTestScenario,
                            arguments = { "uri" : generator1,
                                          "subtest-class": test,
                                          "debug-level-1":str(debuglevel),
                                          "debug-level-2":str(debuglevel2) },
                            monitors = monitors)
        else:
            testrun.addTest(test,
                            arguments = { "uri" : generator1 },
                            monitors = monitors)

    return testrun

def fileparse_callback(option, opt, value, parser):
    assert value is None
    value = []
    rargs = parser.rargs
    while rargs:
        arg = rargs[0]
        if ((arg[:2] == "--" and len(arg) > 2) or
            (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
            break
        else:
            value.append(arg)
            del rargs[0]

    setattr(parser.values, option.dest, value)

if __name__ == "__main__":
    """ Run the given files with the given testscript """
    # We should have arguments for choosing
    # _ A top output directory (topdir)
    # _ The list of tests to run
    parser = OptionParser()
    parser.add_option("-t", "--tests", dest="tests",
                      action="callback", callback=fileparse_callback,
                      help="test(s) to run on the given files",
                      default=[])
    parser.add_option("-f", "--files", dest="files",
                      help="list of file and/or directories to test",
                      action="callback", callback=fileparse_callback,
                      default=[])
    parser.add_option("-o", "--output", dest="output",
                      help="top-level output directory (default: current)", metavar="DIRECTORY",
                      default=None)
    parser.add_option("-v", "--valgrind", dest="valgrind",
                     help="Run within valgrind",
                     action="store_true",
                     default=False)
    parser.add_option("-V", "--verbose", dest="verbose",
                     help="Verbose output",
                     action="store_true",
                     default=False)
    parser.add_option("-n", "--nonrecursive", dest="recursive",
                      help="Don't go recursively in directories",
                      action="store_false",
                      default=True)
    parser.add_option("-x", "--extreme", dest="extreme",
                      help="Valgrind failed test (even without -v)",
                      action="store_true",
                      default=False)
    parser.add_option("-d", "--debuglevel", dest="debuglevel", type="int",
                      default=2, help="GStreamer debug level (default: 2)")
    parser.add_option("-D", "--debuglevel2", dest="debuglevel2", type="int",
                      default=5, help="GStreamer debug level for 2nd run (default: 5)")
    parser.add_option("-a", "--accept", dest="accept",
                      help="Coma-separated list of file globs to limit the tests to.",
                      default=None, metavar="EXTENSIONS")
    parser.add_option("-e", "--exclude", dest="exclude",
                      help="Coma-separated list of file globs to exclude from tests.",
                      default=None, metavar="EXTENSIONS")
    parser.add_option("-S", "--simultaneous", dest="maxnbtests",
                      type="int", default=1, help="Maximum number of simultaneous tests (default:1)")
    parser.add_option("-l", "--no-reruns", dest="rerun",
                      action="store_false", default=True,
                      help="Don't rerun test with higher debugging if it failed")
    parser.add_option("-p", "--playlist", dest="playlist",
                      default=None, metavar="PLAYLIST",
                      help="Playlist file containing one URI per line")
    parser.add_option("-m", "--mysql", dest="usemysql",
                      default=False, action="store_true",
                      help="Connect to a MySQL database for storage")
    (options, args) = parser.parse_args(sys.argv[1:])
    files = options.files
    tests = options.tests
    if options.accept:
        acceptlist = options.accept.split(",")
    else:
        acceptlist = []

    if options.exclude:
        rejectlist = options.exclude.split(",")
    else:
        rejectlist = []

    if not (len(files) or options.playlist) and not len(tests):
        parser.print_help()
        tests = utils.list_available_tests()
        print "Available tests:"
        for name, desc, cls in tests:
            print "\t% -20s : %s" % (name, desc)
        scenarios = utils.list_available_scenarios()
        print "Available scenarios:"
        for name, desc, cls in scenarios:
            print "\t% -20s : %s" % (name, desc)
        sys.exit()
    else:
        testrun = create_testrun(files=files, testscripts=tests,
                                 topdir=options.output,
                                 recursive=options.recursive,
                                 extreme=options.extreme,
                                 valgrinding=options.valgrind,
                                 debuglevel=options.debuglevel,
                                 debuglevel2=options.debuglevel2,
                                 acceptlist=acceptlist,
                                 rejectlist=rejectlist,
                                 maxnbtests=options.maxnbtests,
                                 rerun=options.rerun,
                                 playlist=options.playlist)

        tester = GstMediaTestClient(testrun, verbose=options.verbose,
                                    usemysql=options.usemysql)
        tester.run()
