#!/usr/bin/python3
###############################################################################
#
# Copyright 2020 OpenHW Group
#
# Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://solderpad.org/licenses/
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
#
###############################################################################
# MetricsCI script launched by GitHub Actions.
# See ../.github/workflows/metrics-regress.yml.
# Not intended to be launched manually, but if you _have_ to here's an example:
# ENV vars needed by metrics-regress:
#     $ export GITHUB_EVENT_NAME=push
#     $ export GITHUB_REF=master
# You need to have saved METRICS_CI_TOKEN in a safe place.
#     $ export METRICS_CI_TOKEN=6Pcc5hQoIKEn8Pjz+lvjqG+C1SY=
#     $ ./metrics-regress cv32e40p_ci_check_regression main-core-v-verif-openhwgroup


import json
import http.client
import argparse
import os
import time
import math

def make_http_request( req_type, endpoint, params=None ):
    headers = { 'Content-Type': 'application/json',
                'Private-Token': str(os.environ['METRICS_CI_TOKEN'])
               }

    conn = http.client.HTTPSConnection(server)
    conn.request(req_type, endpoint, params, headers)
    response = conn.getresponse()
    data = response.read()
    regressionData = json.loads(data.decode('utf-8'))
    conn.close()

    return response, regressionData


## Parse arguments to get regression name and project ID
parser = argparse.ArgumentParser(prog='metrics-regress',
                                 description='Launch a regression on the Metrics platform and query results')
parser.add_argument('regressionName', help='The name of the regression to run')
parser.add_argument('projectId',      help='The ID of the Metrics project')
args = parser.parse_args()

## Server
server =  'openhwgroup.metrics.ca:443'

## API Endpoints
postRegression = '/api/v1/projects/'+args.projectId+'/regressionRuns'
getRegressionRunInfo = '/api/v1/projects/'+args.projectId+'/regressionRuns/'

## Start regression
reqParams = {}
reqParams['regressionName'] = args.regressionName

# Determine the git reference to pass to Metrics. For PRs, the reference
# is of the format refs/pull/<PR-number>/merge
if str(os.environ['GITHUB_EVENT_NAME']) == 'pull_request_target':
    reqParams['branch'] = 'refs/pull/' + str(os.environ['PR_NUMBER']) + '/merge'
else:
    reqParams['branch'] = str(os.environ['GITHUB_REF'])
params = json.dumps(reqParams)

response, regressionData = make_http_request('POST', postRegression, params)

## Check response
if response.status != 201:
    print('Error, regression was not started. Response: ' + str(response.status) + ':' \
          + str(response.reason) + ' ' + str(regressionData))
    print('Exit with code 1')
    exit(1)
else:
    print('Regression started. Id = ' + regressionData['id'])

## Start polling regression status
regressionRunId = regressionData['id']

while True:
    time.sleep(10)
    response, regressionData = make_http_request('GET', getRegressionRunInfo+regressionRunId)
    if response.status == 200:
        if 'complete' in regressionData['status']:
            print('Regression complete')
            break
        if 'buildFailed' in regressionData['status']:
            print('A build has failed. No tests will be run')
            print('Debug at: https://openhwgroup.metrics.ca/' + args.projectId + \
                  '/results/regressionRuns/' + regressionRunId)
            exit(1)

## Print test status
print('\n')
print('Regression results')
print('==================')
print('Total number of tests: ' + str(regressionData['testRuns']['total']))
print('Passed tests: ' + str(regressionData['testRuns']['passed']))
print('Failed tests: ' + str(regressionData['testRuns']['failed']))
print('Incomplete tests: ' + str(regressionData['testRuns']['incomplete']))
print('\n')

## Poll for coverage data
while True:
    time.sleep(10)
    response, regressionData = make_http_request('GET', getRegressionRunInfo+regressionRunId)
    if response.status == 200:
        if regressionData['functionalCoverage'] is not None :
            break

## Print functional coverage
print('Coverage results')
print('================')
print('Functional: ' + str(math.trunc(regressionData['functionalCoverage']*100)/100))
if regressionData['assertionCoverage'] is not None:
    print('Assertion: ' + str(math.trunc(regressionData['assertionCoverage']*100) /100))
if regressionData['lineCoverage'] is not None:
    print('Code (block): ' + str(math.trunc(regressionData['lineCoverage']*100) /100))
print('\n')

print('Full results at: https://openhwgroup.metrics.ca/' + args.projectId + \
      '/results/regressionRuns/' + regressionRunId)

## Set the exit code to be used by github action
if regressionData['testRuns']['failed'] > 0 or \
   regressionData['testRuns']['incomplete'] > 0:
    print('One or more tests has failed/is incomplete. Exit with code 1.')
    exit(1)
else:
    print('All tests have passed. Exit with code 0.')
    exit(0)
