Skip to content

Commit

Permalink
[client] Store support configuration file
Browse files Browse the repository at this point in the history
  • Loading branch information
csordasmarton committed Mar 13, 2020
1 parent 52e98da commit b9ea9f2
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 6 deletions.
12 changes: 10 additions & 2 deletions docs/web/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,9 @@ a database.
to the database.

```
usage: CodeChecker store [-h] [-t {plist}] [-n NAME] [--tag TAG] [-f]
[--url PRODUCT_URL]
usage: CodeChecker store [-h] [-t {plist}] [-n NAME] [--tag TAG]
[--trim-path-prefix [TRIM_PATH_PREFIX [TRIM_PATH_PREFIX ...]]]
[--config CONFIG_FILE] [-f] [--url PRODUCT_URL]
[--verbose {info,debug,debug_analyzer}]
[file/folder [file/folder ...]]
Expand Down Expand Up @@ -192,6 +193,13 @@ optional arguments:
removing "/a/b/" prefix will store files like c/x.cpp
and c/y.cpp. If multiple prefix is given, the longest
match will be removed.
--config CONFIG_FILE Allow the configuration from an explicit JSON based
configuration file. The value of the 'store' key in
the config file will be emplaced as command line
arguments. The format of configuration file is: {
"enabled": true, "store": [ "--name=run_name", "--
tag=my_tag" "--url=http://codechecker.my/MyProduct"
]}.
-f, --force Delete analysis results stored in the database for the
current analysis run's name and store only the results
reported in the 'input' files. (By default,
Expand Down
30 changes: 29 additions & 1 deletion web/client/codechecker_client/cmd/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,23 @@ def add_arguments_to_parser(parser):
"If multiple prefix is given, the longest match "
"will be removed.")

parser.add_argument('--config',
dest='config_file',
required=False,
help="Allow the configuration from an explicit JSON "
"based configuration file. The value of the "
"'store' key in the config file will be "
"emplaced as command line arguments. The format "
"of configuration file is: "
"{"
" \"enabled\": true,"
" \"store\": ["
" \"--name=run_name\","
" \"--tag=my_tag\""
" \"--url=http://codechecker.my/MyProduct\""
" ]"
"}.")

parser.add_argument('-f', '--force',
dest="force",
default=argparse.SUPPRESS,
Expand Down Expand Up @@ -173,7 +190,18 @@ def add_arguments_to_parser(parser):
"'[http[s]://]host:port/Endpoint'.")

logger.add_verbose_arguments(parser)
parser.set_defaults(func=main)
parser.set_defaults(func=main,
func_process_config_file=process_config_file)


def process_config_file(args):
"""
Handler to get config file options.
"""
if args.config_file and os.path.exists(args.config_file):
cfg = util.load_json_or_empty(args.config_file, default={})
if cfg.get("enabled"):
return cfg.get('store', [])


def __get_run_name(input_list):
Expand Down
36 changes: 33 additions & 3 deletions web/tests/functional/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@

import os
import shutil
import sys

from libtest import codechecker
from libtest import env
from libtest import project


# Test workspace should be initialized in this module.
Expand All @@ -27,17 +30,40 @@ def setup_package():
# Set the TEST_WORKSPACE used by the tests.
os.environ['TEST_WORKSPACE'] = TEST_WORKSPACE

test_project = 'cpp'
test_project_path = project.path(test_project)
project_info = project.get_info(test_project)

# Create a basic CodeChecker config for the tests, this should
# be imported by the tests and they should only depend on these
# configuration options.
codechecker_cfg = {
'workspace': TEST_WORKSPACE,
'check_env': env.test_env(TEST_WORKSPACE),
'viewer_host': 'localhost',
'viewer_product': 'db_cleanup'
'reportdir': os.path.join(TEST_WORKSPACE, 'reports'),
'checkers': ['-d', 'core.CallAndMessage',
'-e', 'core.StackAddressEscape']
}

env.export_test_cfg(TEST_WORKSPACE, {'codechecker_cfg': codechecker_cfg})
# Start or connect to the running CodeChecker server and get connection
# details.
print("This test uses a CodeChecker server... connecting...")
server_access = codechecker.start_or_get_server()
server_access['viewer_product'] = 'config'
codechecker.add_test_package_product(server_access, TEST_WORKSPACE)

# Extend the checker configuration with the server access.
codechecker_cfg.update(server_access)

ret = codechecker.analyze(codechecker_cfg, test_project_path)
if ret:
sys.exit(1)

test_config = {
'test_project': project_info,
'codechecker_cfg': codechecker_cfg}

env.export_test_cfg(TEST_WORKSPACE, test_config)


def teardown_package():
Expand All @@ -47,5 +73,9 @@ def teardown_package():
# and print out the path.
global TEST_WORKSPACE

check_env = env.import_test_cfg(TEST_WORKSPACE)[
'codechecker_cfg']['check_env']
codechecker.remove_test_package_product(TEST_WORKSPACE, check_env)

print("Removing: " + TEST_WORKSPACE)
# shutil.rmtree(TEST_WORKSPACE)
87 changes: 87 additions & 0 deletions web/tests/functional/config/test_store_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#
# -----------------------------------------------------------------------------
# The CodeChecker Infrastructure
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
# -----------------------------------------------------------------------------

"""
Test store configuration file.
"""


import json
import os
import subprocess
import unittest

from libtest import env


class TestStoreConfig(unittest.TestCase):
_ccClient = None

def setUp(self):

# TEST_WORKSPACE is automatically set by test package __init__.py .
self.test_workspace = os.environ['TEST_WORKSPACE']
self.codechecker_cfg = env.import_codechecker_cfg(self.test_workspace)

test_class = self.__class__.__name__
print('Running ' + test_class + ' tests in ' + self.test_workspace)

# Get the CodeChecker cmd if needed for the tests.
self._codechecker_cmd = env.codechecker_cmd()

self.config_file = os.path.join(self.test_workspace,
"codechecker.json")

def test_valid_config(self):
""" Store with a valid configuration file. """
with open(self.config_file, 'w+',
encoding="utf-8", errors="ignore") as config_f:
json.dump({
'enabled': True,
'store': [
'--name=' + 'store_config',
'--url=' + env.parts_to_url(self.codechecker_cfg),
self.codechecker_cfg['reportdir']]}, config_f)

store_cmd = [env.codechecker_cmd(), 'store', '--config',
self.config_file]

subprocess.check_output(
store_cmd, encoding="utf-8", errors="ignore")

def test_invalid_config(self):
""" Store with an invalid configuration file. """
with open(self.config_file, 'w+',
encoding="utf-8", errors="ignore") as config_f:
json.dump({
'enabled': True,
'store': ['--dummy-option']}, config_f)

store_cmd = [env.codechecker_cmd(), 'store',
'--name', 'store_config',
'--config', self.config_file,
'--url', env.parts_to_url(self.codechecker_cfg),
self.codechecker_cfg['reportdir']]

with self.assertRaises(subprocess.CalledProcessError):
subprocess.check_output(
store_cmd, encoding="utf-8", errors="ignore")

def test_empty_config(self):
""" Store with an empty configuration file. """
with open(self.config_file, 'w+',
encoding="utf-8", errors="ignore") as config_f:
config_f.write("")

store_cmd = [env.codechecker_cmd(), 'store',
'--name', 'store_config',
'--config', self.config_file,
'--url', env.parts_to_url(self.codechecker_cfg),
self.codechecker_cfg['reportdir']]

subprocess.check_output(
store_cmd, encoding="utf-8", errors="ignore")

0 comments on commit b9ea9f2

Please sign in to comment.