#!/usr/bin/python3

#
# Copyright (C) 2017 Red Hat, Inc.
#
# Cockpit 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.
#
# Cockpit 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 Cockpit; If not, see <http://www.gnu.org/licenses/>.
#

import argparse
import os
import re
import subprocess
import sys

import cdp

tap_line_re = re.compile(r'^(ok [0-9]+|not ok [0-9]+|bail out!|[0-9]+\.\.[0-9]+|# )', re.IGNORECASE)

parser = argparse.ArgumentParser(description="A CDP driver for QUnit which outputs TAP")
parser.add_argument("server", help="path to the test-server and the test page to run", nargs=argparse.REMAINDER)

# Strip prefix from url
# We need this to compensate for automake test generation behavior:
# The tests are called with the path (relative to the build directory) of the testfile,
# but from the build directory. Some tests make assumptions regarding the structure of the
# filename. In order to make sure that they receive the same name, regardless of actual
# build directory location, we need to strip that prefix (path from build to source directory)
# from the filename
parser.add_argument("--strip", dest="strip", help="strip prefix from test file paths")

opts = parser.parse_args()

# argparse sometimes forgets to remove this on argparse.REMAINDER args
if opts.server[0] == '--':
    opts.server = opts.server[1:]

# The test file is the last argument, but 'server' might contain arbitrary
# amount of options. We cannot express this with argparse, so take it apart
# manually.
opts.test = opts.server[-1]
opts.server = opts.server[:-1]

if opts.strip and opts.test.startswith(opts.strip):
    opts.test = opts.test[len(opts.strip):]

cdp = cdp.CDP("C.utf8")

try:
    cdp.browser.path(cdp.show_browser)
except SystemError:
    print('1..0 # skip web browser not found')
    sys.exit(0)

# pass the address through a separate fd, so that we can see g_debug() messages (which go to stdout)
(addr_r, addr_w) = os.pipe()
env = os.environ.copy()
env["TEST_SERVER_ADDRESS_FD"] = str(addr_w)

server = subprocess.Popen(opts.server,
                          stdin=subprocess.DEVNULL,
                          pass_fds=(addr_w,),
                          close_fds=True,
                          env=env)
os.close(addr_w)
address = os.read(addr_r, 1000).decode()
os.close(addr_r)

cdp.invoke("Page.navigate", url=address + '/' + opts.test)

success = True
ignore_resource_errors = False

for t, message in cdp.read_log():

    # fail on browser level errors
    if t == 'cdp':
        if message['level'] == "error":
            if ignore_resource_errors and "Failed to load resource" in message["text"]:
                continue
            success = False
            break
        else:
            continue

    if message == 'cockpittest-tap-done':
        break
    elif message == 'cockpittest-tap-error':
        success = False
        break
    elif message == 'cockpittest-tap-expect-resource-error':
        ignore_resource_errors = True
        continue

    # TAP lines go to stdout, everything else to stderr
    if tap_line_re.match(message):
        if message.startswith('not ok'):
            success = False
        print(message)
    else:
        print(message, file=sys.stderr)


server.terminate()
server.wait()
cdp.kill()

if not success:
    sys.exit(1)
