Пример #1
0
def test_check_deprecated_playbook(repo):
    """
    Given
    - An non-deprecated playbook yml.

    When
    - Running check_deprecated method.

    Then
    - Ensure the predefined deprecated ignored errors list includes the deprecated default error list only.
    """
    pack = repo.create_pack('pack')
    playbook = pack.create_integration('playbook-somePlaybook')
    test_file_path = join(git_path(), 'demisto_sdk', 'tests', 'test_files')
    valid_deprecated_playbook_file_path = join(
        test_file_path, 'Packs', 'CortexXDR', 'Playbooks',
        'Valid_Deprecated_Playbook.yml')
    playbook.yml.write_dict(get_yaml(valid_deprecated_playbook_file_path))
    files_path = playbook.yml.path
    with ChangeCWD(repo.path):
        base_validator = BaseValidator(ignored_errors={})
        base_validator.check_deprecated(files_path)
    assert base_validator.predefined_deprecated_ignored_errors == {
        files_path: DEPRECATED_IGNORE_ERRORS_DEFAULT_LIST
    }
Пример #2
0
class TestUnitTestsGenerator:
    test_files_path = Path(__file__, git_path(), 'demisto_sdk', 'commands', 'generate_unit_tests', 'tests', 'test_files')
    input_path = None
    output_dir = None

    @classmethod
    def setup_class(cls):
        cls.input_path = str(Path(cls.test_files_path, 'inputs', 'malwarebazaar.py'))
        cls.output_dir = str(Path(cls.test_files_path, 'outputs'))

    @pytest.mark.parametrize('args, expected_result', ARGS)
    def test_tests_generated_successfully(self, mocker, args, expected_result):
        """
        Given
        - input arguments for the command
        - desired path to generate the test file into.

        When
        - generating config file from the postman collection

        Then
        - ensure the config file is generated
        - the config file should be identical to the one we have under resources folder
        """

        mocker.patch.object(UnitTestsGenerator, "execute_commands_into_dict", return_value=(EXAMPLES, []))

        output_path = Path(self.output_dir, 'malwarebazaar_test.py')
        desired = Path(self.output_dir, expected_result)

        run_generate_unit_tests(
            input_path=self.input_path,
            commands=args.get('commands', ''),
            output_dir=self.output_dir,
            examples='',
            insecure=False,
            use_demisto=False,
            append=False
        )

        with open(output_path, 'r') as f:
            output_source = f.read()

        with open(desired, 'r') as f:
            output_desired = f.read()

        try:
            assert compare_ast(parse(output_source), parse(output_desired))
        finally:
            if output_path.exists():
                os.remove(output_path)
Пример #3
0
def _testutil_create_postman_collection(dest_path,
                                        with_request: dict = None,
                                        no_auth: bool = False):
    default_collection_path = os.path.join(
        git_path(), 'demisto_sdk', 'commands', 'postman_codegen', 'tests',
        'test_files', 'VirusTotal.postman_collection.json')
    with open(default_collection_path, mode='r') as f:
        collection = json.load(f)

    if with_request:
        collection['item'].append(with_request)

    if no_auth:
        del collection['auth']

    with open(dest_path, mode='w') as f:
        json.dump(collection, f)
Пример #4
0
 def test_update_tests_on_integration_with_test_playbook(self):
     """
     Given
         - An integration file.
     When
         - Run format on the integration
     Then
         - Ensure run_format return value is 0
         - Ensure `tests` field gets the Test Playbook ID
     """
     test_files_path = os.path.join(git_path(), 'demisto_sdk', 'tests')
     vmware_integration_yml_path = os.path.join(test_files_path, 'test_files', 'content_repo_example', 'Packs',
                                                'VMware',
                                                'Integrations', 'integration-VMware.yml')
     formatter = IntegrationYMLFormat(input=vmware_integration_yml_path, output='')
     res = formatter.update_tests()
     assert res is None
     assert formatter.data.get('tests') == ['VMWare Test']
def test_extract_to_package_format_py(pack, mocker, tmp_path):
    mocker.patch.object(YmlSplitter, 'extract_image', return_value='12312321')
    mocker.patch(
        'demisto_sdk.commands.split.ymlsplitter.get_python_version',
        return_value='2.7'
    )
    mocker.patch(
        'demisto_sdk.commands.split.ymlsplitter.get_pipenv_dir',
        return_value=os.path.join(git_path(), 'demisto_sdk/tests/test_files/default_python2')
    )
    mocker.patch(
        'demisto_sdk.commands.split.ymlsplitter.get_pip_requirements',
        return_value="""certifi==2017.11.5
chardet==3.0.4
idna==2.6
olefile==0.44
PyYAML==3.12
requests==2.18.4
urllib3==1.22
"""
    )
    integration = pack.create_integration('Sample')
    integration.create_default_integration()
    out = tmp_path / 'TestIntegration'
    non_sorted_imports = 'from CommonServerPython import *\nimport datetime\nimport json'
    integration.yml.update(
        {
            'image': '',
            'script': {
                'type': 'python',
                'script': non_sorted_imports
            }
        }
    )
    extractor = YmlSplitter(input=integration.yml.path,
                            output=str(out), file_type='integration')
    extractor.extract_to_package_format()
    with open(out / 'TestIntegration.py', encoding='utf-8') as f:
        file_data = f.read()
        # check imports are sorted
        assert non_sorted_imports not in file_data
Пример #6
0
class TestCodeGenerator:
    test_files_path = os.path.join(git_path(), 'demisto_sdk', 'commands', 'generate_integration', 'tests', 'test_files')
    test_integration_dir = os.path.join(test_files_path, 'VirusTotalTest')
    autogen_config_path = os.path.join(test_files_path, 'VirusTotal-autogen-config.json')

    def test_py_code_generated_from_config(self, mocker, tmpdir):
        """
        This test will fail for every change in the generated python code!!

        This is general happy path test, the purpose of this test is not to test something specifically
        but to make sure if something changed in generated python file, this test will fail because it is not
        identical with the actual result.

        If this test fails, validate that the reason for the failure is valid and then
        update the test python file under test_files folder.

        Given
        - code genereator config file, which was generated for VirusTotal api (4 commands)

        When
        - generating code from it

        Then
        - ensure code is generated
        - esnrue the code is identical to what is stored under test_files folder
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator, 'get_docker_image_latest_tag_request', return_value='3.8.6.12176')

        autogen_config = None
        with open(self.autogen_config_path, mode='r') as f:
            config_dict = json.load(f)
            config_dict['fix_code'] = True
            autogen_config = IntegrationGeneratorConfig(**config_dict)

        code = autogen_config.generate_integration_python_code()

        with open(os.path.join(self.test_integration_dir, 'VirusTotalTest.py'), mode='r') as f:
            expected_code = f.read()

            assert expected_code == code

    def test_yml_generated_from_config(self, mocker):
        """
        This test will fail for every change in the generated integration yml file!!

        This is general happy path test, the purpose of this test is not to test something specifically
        but to make sure if something changed in generated yml file, this test will fail because it is not
        identical with the actual result.

        If this test fails, validate that the reason for the failure is valid and then
        update the test python file under test_files folder.

        Given
        - generated xsoar integration config file for VirusTotal Test

        When
        - generating integration yml file

        Then
        - ensure it generates the yml successfully and the yml is the exact as expected yml from test_files folder
       """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator, 'get_docker_image_latest_tag_request', return_value='3.8.6.12176')

        with open(self.autogen_config_path, mode='r') as f:
            config_dict = json.load(f)
            config_dict['fix_code'] = True
            autogen_config = IntegrationGeneratorConfig(**config_dict)

        yaml_obj = autogen_config.generate_integration_yml().to_dict()
        with open(os.path.join(self.test_integration_dir, 'VirusTotalTest.yml'), mode='r') as f:
            expected_yml = yaml.load(f)

        assert expected_yml == yaml_obj

    def test_generate_integration_package(self, tmpdir, mocker):
        """
        Given
        - generated xsoar integration config file for VirusTotal Test

        When
        - generating xsoar integration package from config file

        Then
        - ensure VirusTotalTest dir created
        - ensure VirusTotalTest dir contains VirusTotalTest.py
        - ensure VirusTotalTest dir contains VirusTotalTest.yml
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator, 'get_docker_image_latest_tag_request', return_value='3.8.6.12176')

        with open(self.autogen_config_path, mode='r') as f:
            config_dict = json.load(f)
            config_dict['fix_code'] = True
            autogen_config = IntegrationGeneratorConfig(**config_dict)

        autogen_config.generate_integration_package(
            output_dir=tmpdir
        )

        assert os.path.isdir(Path(tmpdir, 'VirusTotalTest'))
        assert os.path.isfile(Path(tmpdir, 'VirusTotalTest', 'VirusTotalTest.py'))
        assert os.path.isfile(Path(tmpdir, 'VirusTotalTest', 'VirusTotalTest.yml'))

    def test_generate_unified_integration_yml(self, tmpdir, mocker):
        """
        Given
        - generated xsoar integration config file for VirusTotal Test

        When
        - generating xsoar integration unified yml from config file

        Then
        - ensure integration-VirusTotalTest.yml exists
        - ensure the unified file contains the script
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator, 'get_docker_image_latest_tag_request', return_value='3.8.6.12176')

        autogen_config = None
        with open(self.autogen_config_path, mode='r') as f:
            config_dict = json.load(f)
            config_dict['fix_code'] = True
            autogen_config = IntegrationGeneratorConfig(**config_dict)

        assert autogen_config
        autogen_config.generate_integration_package(
            output_dir=tmpdir,
            is_unified=True
        )

        assert os.path.isfile(Path(tmpdir, 'integration-VirusTotalTest.yml'))
        with open(Path(tmpdir, 'integration-VirusTotalTest.yml'), mode='r') as f:
            actual_unified_yml = f.read()
            assert actual_unified_yml.find('class Client(BaseClient):')
            assert actual_unified_yml.find('- display: Trust any certificate')

    def test_query_response_root_object(self):
        """
        Given
        - integration config file
        - with command test-scan
        - with root object "scans"

        When
        - generating the integration py and yml files

        Then
        - ensure in the code we return response.get('scans')
        - ensure in yml, we generate outputs for scans object, and not to the whole response
        """
        with open(os.path.join(self.test_files_path, 'VirusTotal-autogen-config.json'), mode='r') as f:
            config_dict = json.load(f)

        config = IntegrationGeneratorConfig(**config_dict)
        test_command = _testutil_create_command(name='test-scan', root_object='scans', context_path='TestScan', outputs=[
            IntegrationGeneratorOutput(
                name='total_count',
                description='',
                type_='Number'
            ),
            IntegrationGeneratorOutput(
                name='scans.field1',
                description='',
                type_='String'
            ),
        ])
        config.commands.append(test_command)

        integration_code = config.generate_integration_python_code()
        integration_yml = config.generate_integration_yml()
        integration_yml_str = yaml.dumps(integration_yml.to_dict())

        assert "outputs=response.get('scans')" in integration_code
        assert 'contextPath: VirusTotalTest.TestScan.scans.field1' in integration_yml_str
        assert 'contextPath: VirusTotalTest.TestScan.total_count' in integration_yml_str
Пример #7
0
import demisto_sdk.commands.common.constants as constants
from demisto_sdk.commands.common.legacy_git_tools import git_path

GIT_ROOT = "{}".format(git_path())
INVALID_PLAYBOOK_PATH = f"{GIT_ROOT}/demisto_sdk/tests/test_files/Playbooks.playbook-invalid.yml"
VALID_TEST_PLAYBOOK_PATH = f"{GIT_ROOT}/demisto_sdk/tests/test_files/Playbooks.playbook-test.yml"
VALID_BETA_PLAYBOOK_PATH = f"{GIT_ROOT}/demisto_sdk/tests/test_files/beta-playbook-valid.yml"
VALID_PLAYBOOK_ARCSIGHT_ADD_DOMAIN_PATH = f"{GIT_ROOT}/demisto_sdk/tests/test_files/Playbooks." \
                                          f"playbook-ArcSight_Add_Domain_Indicators.yml"
INVALID_INTEGRATION_NO_TESTS = f'{GIT_ROOT}/demisto_sdk/tests/test_files/non-valid-integration-no-test-playbooks.yml'
INVALID_INTEGRATION_NON_CONFIGURED_TESTS = f'{GIT_ROOT}/demisto_sdk/tests/test_files/' \
                                           f'non-valid-integration-test-not-configured.yml'
TEST_PLAYBOOK = f'{GIT_ROOT}/demisto_sdk/tests/test_files/playbook-TestPlaybooks.yml'

VALID_PYTHON_INTEGRATION_TEST_PATH = f"{GIT_ROOT}/demisto_sdk/tests/test_files/integration_test.py"
VALID_PYTHON_INTEGRATION_PATH = f"{GIT_ROOT}/demisto_sdk/tests/test_files/integration-test.py"
VALID_METADATA1_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/1.pack_metadata.json'
VALID_METADATA2_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/2.pack_metadata.json'
VALID_DESCRIPTION_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/integration-test_description.md'
VALID_README_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/integration-test_README.md'
VALID_IMAGE_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/integration-test_image.png'
NOT_VALID_IMAGE_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/default.png'
VALID_PIPEFILE_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/Pipfile'
VALID_PIPEFILE_LOCK_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/Pipfile.lock'
VALID_PACK_IGNORE_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/.pack-ignore'
VALID_SECRETS_IGNORE_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/.secrets-ignore'
VALID_CLASSIFIER_PATH = f'{GIT_ROOT}/demisto_sdk/tests/test_files/classifier.json'
VALID_JSON_FILE_FOR_UNIT_TESTING = f'{GIT_ROOT}/demisto_sdk/tests/test_files/fake_pack/Integrations/' \
                                   f'test_data/results.json'
VALID_DOC_FILES_PATH_FOR_UNIT_TESTING = f"{GIT_ROOT}/demisto_sdk/tests/test_files/content_slim/Packs/Sample01/" \
                                        f"doc_files/sample_packs.png"
Пример #8
0
import os
from typing import NamedTuple

import click
import pytest
from git import Repo

from demisto_sdk.commands.common.git_content_config import (GitContentConfig,
                                                            GitCredentials,
                                                            GitProvider)
from demisto_sdk.commands.common.handlers import JSON_Handler
from demisto_sdk.commands.common.legacy_git_tools import git_path

json = JSON_Handler()
GIT_ROOT = git_path()
VALID_GITLAB_RESPONSE = f"{GIT_ROOT}/demisto_sdk/tests/test_files/valid_gitlab_search_response.json"

DEFAULT_GITHUB_BASE_API = 'https://raw.githubusercontent.com/demisto/content'


class Urls(NamedTuple):
    urls: list


class TestGitContentConfig:
    @pytest.mark.parametrize(
        'url, repo_name',
        [
            ('ssh://[email protected]/demisto/content-dist.git', 'demisto/content-dist'),
            ('[email protected]:demisto/content-dist.git', 'demisto/content-dist'),
            # clone using github ssh example
Пример #9
0
class TestOpenAPICodeGen:
    test_files_path = os.path.join(git_path(), 'demisto_sdk', 'tests', 'test_files')
    swagger_path = os.path.join(test_files_path, 'swagger_pets.json')

    def init_integration(self):
        base_name = 'TestSwagger'
        integration = OpenAPIIntegration(self.swagger_path, base_name,
                                         '-'.join(base_name.split(' ')).lower(),
                                         base_name.replace(' ', ''),
                                         unique_keys='id',
                                         root_objects='Pet')

        integration.load_file()
        return integration

    def test_config_file(self, mocker):
        """
        Scenario: Generating an integration from a swagger file

        Given
            - A swagger file
        When
            - Generating the integration configuration file for the swagger file
        Then
            - Ensure the configuration file is generated correctly
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator, 'get_docker_image_latest_tag_request', return_value='3.8.6.12176')

        integration = self.init_integration()
        integration.generate_configuration()

        with open(os.path.join(self.test_files_path, 'swagger_config.json'), 'rb') as config_path:
            config = json.load(config_path)

        assert json.dumps(integration.configuration) == json.dumps(config)

    def test_yaml_file(self, mocker):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
        When
           - Generating the integration yaml
        Then
           - Ensure the yaml file is generated correctly
       """
        import yaml

        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator, 'get_docker_image_latest_tag_request', return_value='3.8.6.12176')
        integration = self.init_integration()

        with open(os.path.join(self.test_files_path, 'swagger_yaml.yml'), 'rb') as yaml_file:
            expected_yaml = yaml.safe_load(yaml_file)

        yaml_obj = integration.generate_yaml().to_dict()

        assert yaml.dump(yaml_obj) == yaml.dump(expected_yaml)

    def test_python_file(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
        When
           - Generating the integration python code
        Then
           - Ensure the python file is generated correctly
       """
        integration = self.init_integration()

        with open(os.path.join(self.test_files_path, 'swagger_python.py'), 'r') as py_file:
            expected_py = py_file.read()

        py = integration.generate_python_code()

        assert py == expected_py

    def test_get_command_function(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file
        When
           - Generating a command function and a request function for a command
        Then
           - Ensure the commands are generated correctly
        """
        integration = self.init_integration()
        command = [c for c in integration.configuration['commands'] if c['name'] == 'get-pet-by-id'][0]

        command_function, req_function = integration.get_python_command_and_request_functions(command)

        assert command_function == expected_command_function
        assert req_function == expected_request_function

    def test_command_body_args(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file
        When
           - Generating arguments for the command request body
        Then
           - Ensure the arguments are generated correctly
        """
        from demisto_sdk.commands.openapi_codegen.openapi_codegen import \
            BASE_DATA
        integration = self.init_integration()
        command = [c for c in integration.configuration['commands'] if c['name'] == 'create-user'][0]

        expected_args = 'id=user_id, username=user_username, firstName=user_firstname, lastName=user_lastname,' \
                        ' email=user_email, password=user_password, phone=user_phone, userStatus=user_userstatus'

        arguments = integration.process_command_arguments(command)
        body_args = integration.format_params(arguments[3], BASE_DATA, BASE_DATA)
        assert expected_args == body_args

    def test_command_headers(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file
        When
           - Generating headers for the command request
        Then
           - Ensure the headers are generated correctly
        """
        integration = self.init_integration()
        command = [c for c in integration.configuration['commands'] if c['name'] == 'post-pet-upload-image'][0]

        expected_headers = [{'Content-Type': 'multipart/form-data'}]

        assert expected_headers == command['headers']

    def test_change_name_duplications(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file (added command with same summary but different path)
        When
           - Generating functions name.
        Then
           - Ensure that the names of given functions generated correctly.
        """

        integration = self.init_integration()
        assert [c for c in integration.configuration['commands'] if c['name'] == 'post-pet-upload-image'][0]
        assert [c for c in integration.configuration['commands'] if c['name'] ==
                'post-pet-upload-image-by-uploadimage'][0]
Пример #10
0
import json
import os

import pytest
from demisto_sdk.commands.common.legacy_git_tools import git_path
from demisto_sdk.commands.common.tools import get_json, get_yaml
from demisto_sdk.commands.create_id_set.create_id_set import IDSetCreator
from demisto_sdk.commands.generate_docs.generate_integration_doc import (
    append_or_replace_command_in_docs, generate_commands_section,
    generate_integration_doc, generate_setup_section,
    generate_single_command_section, get_command_examples)
from demisto_sdk.commands.generate_docs.generate_script_doc import \
    generate_script_doc

FILES_PATH = os.path.normpath(
    os.path.join(__file__, git_path(), 'demisto_sdk', 'tests', 'test_files'))
FAKE_ID_SET = get_json(os.path.join(FILES_PATH, 'fake_id_set.json'))
TEST_PLAYBOOK_PATH = os.path.join(FILES_PATH, 'playbook-Test_playbook.yml')
TEST_SCRIPT_PATH = os.path.join(FILES_PATH, 'script-test_script.yml')
TEST_INTEGRATION_PATH = os.path.join(FILES_PATH,
                                     'fake_integration/fake_integration.yml')

# common tests


def test_format_md():
    """
        Given
            - A string representing a markdown returned from server with <br> tag

        When
import pytest
from click.testing import CliRunner

import conftest  # noqa: F401
from demisto_sdk.__main__ import main
from demisto_sdk.commands.common.git_util import GitUtil
from demisto_sdk.commands.common.legacy_git_tools import git_path
from demisto_sdk.commands.update_release_notes.update_rn import UpdateRN
from demisto_sdk.commands.update_release_notes.update_rn_manager import \
    UpdateReleaseNotesManager
from demisto_sdk.commands.validate.validate_manager import ValidateManager
from TestSuite.test_tools import ChangeCWD

UPDATE_RN_COMMAND = "update-release-notes"
DEMISTO_SDK_PATH = join(git_path(), "demisto_sdk")
TEST_FILES_PATH = join(git_path(), 'demisto_sdk', 'tests')
AZURE_FEED_PACK_PATH = join(TEST_FILES_PATH, 'test_files', 'content_repo_example', 'Packs', 'FeedAzureValid')
RN_FOLDER = join(git_path(), 'Packs', 'FeedAzureValid', 'ReleaseNotes')
VMWARE_PACK_PATH = join(TEST_FILES_PATH, 'test_files', 'content_repo_example', 'Packs', 'VMware')
VMWARE_RN_PACK_PATH = join(git_path(), 'Packs', 'VMware', 'ReleaseNotes')
THINKCANARY_RN_FOLDER = join(git_path(), 'Packs', 'ThinkCanary', 'ReleaseNotes')


@pytest.fixture
def demisto_client(mocker):
    mocker.patch(
        "demisto_sdk.commands.download.downloader.demisto_client",
        return_valure="object"
    )
Пример #12
0
class TestPostmanCodeGen:
    test_files_path = os.path.join(git_path(), 'demisto_sdk', 'commands',
                                   'postman_codegen', 'tests', 'test_files')
    postman_collection_path = os.path.join(
        test_files_path, 'VirusTotal.postman_collection.json')
    autogen_config_path = os.path.join(test_files_path,
                                       'VirusTotal-autogen-config.json')

    def test_config_generated_successfully(self, mocker):
        """
        This is general happy path test, the purpose of this test is not to test something specifically
        but to make sure if something changed in config file schema or broken, this test will fail because it is not
        identical with the actual result.
        If this test fails, validate that the reason for the failure is valid (like on purpose schema update) and then
        update the test file under resources folder.

        Given
        - Postman collection v2.1 of 4 Virus Total API commands

        When
        - generating config file from the postman collection

        Then
        - ensure the config file is generated
        - the config file should be identical to the one we have under resources folder
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator,
                            'get_docker_image_latest_tag_request',
                            return_value='3.8.6.12176')

        autogen_config = postman_to_autogen_configuration(
            collection_path=self.postman_collection_path,
            name='VirusTotal Test',
            command_prefix='vt-test',
            context_path_prefix='VirusTotalTest')

        with open(self.autogen_config_path, 'r') as config_file:
            expected_config = json.load(config_file)

        assert expected_config == autogen_config.to_dict()

    def test_command_prefix(self):
        """
        Given
        - postman collection with name Virus Total

        When
        - generating config file

        Then
        - ensure command_prefix is virustotal-

        """
        autogen_config = postman_to_autogen_configuration(
            collection_path=self.postman_collection_path,
            command_prefix=None,
            name=None,
            context_path_prefix=None,
            category=None)

        assert autogen_config.command_prefix == 'virustotal'

    def test_context_output_path(self):
        """
        Given
        - postman collection with name Virus Total

        When
        - generating config file

        Then
        - ensure context_output_path of the whole integration is VirusTotal
        """
        autogen_config = postman_to_autogen_configuration(
            collection_path=self.postman_collection_path,
            context_path_prefix=None,
            command_prefix=None,
            name=None,
            category=None)

        assert autogen_config.context_path == 'VirusTotal'

    def test_url_contains_args(self, tmp_path):
        """
        Given
        - postman collection
        - with request Test Report which has variable {{foo}} in the url like: {{url}}/vtapi/v2/test/{{foo}}?resource=https://www.cobaltstrike.com/

        When
        - generating config file

        Then
        - integration code, the command test-report will contain foo argument passed to the url
        - integration yml, the command test-report will contain foo arg
        """
        path = tmp_path / 'test-collection.json'
        _testutil_create_postman_collection(
            dest_path=path,
            with_request={
                "name": "Test Report",
                "request": {
                    "method": "GET",
                    "header": [],
                    "url": {
                        "raw":
                        "{{url}}/vtapi/v2/test/{{foo}}?resource=https://www.cobaltstrike.com/",
                        "host": ["{{url}}"],
                        "path": ["vtapi", "v2", "test", "{{foo}}"],
                        "query": [{
                            "key": "resource",
                            "value": "https://www.cobaltstrike.com/"
                        }]
                    },
                    "description": "Test Report description"
                }
            })

        config = postman_to_autogen_configuration(collection_path=path,
                                                  name='VirusTotal',
                                                  context_path_prefix=None,
                                                  command_prefix=None)

        integration_code = config.generate_integration_python_code()
        integration_obj = config.generate_integration_yml()
        integration_yml = yaml.dump(integration_obj.to_dict())

        assert "foo = args.get('foo')" in integration_code
        assert "def test_report_request(self, foo, resource):" in integration_code
        assert "'GET', f'vtapi/v2/test/{foo}', params=params, headers=headers)" in integration_code

        assert 'name: foo' in integration_yml

    def test_apikey_passed_as_header(self, tmpdir):
        """
        Scenario: sometimes the auth method will not be defined under auth section, but as plain header Authorization

        Given
        - postman collection
        - with no auth defined
        - with request with headers:
            - "Authorization" header with value "SWSS {{apikey}}"
            - and other typical headers like Content-Type and Accept

        When
        - generating config file

        Then
        - config file should contain auth
        """
        path = Path(tmpdir, 'config.json')
        _testutil_create_postman_collection(dest_path=path,
                                            with_request={
                                                "name": "Test Report",
                                                "request": {
                                                    "method":
                                                    "GET",
                                                    "header": [{
                                                        "key":
                                                        "Accept",
                                                        "value":
                                                        "application/json"
                                                    }, {
                                                        "key":
                                                        "Content-Type",
                                                        "value":
                                                        "application/json"
                                                    }, {
                                                        "key":
                                                        "Authorization",
                                                        "value":
                                                        "SSWS {{apikey}}"
                                                    }],
                                                    "url": {
                                                        "raw": "{{url}}/test/",
                                                        "host": ["{{url}}"],
                                                        "path": [
                                                            "test",
                                                        ]
                                                    },
                                                    "description":
                                                    "Test Report description"
                                                }
                                            },
                                            no_auth=True)

        config = postman_to_autogen_configuration(collection_path=path,
                                                  name=None,
                                                  command_prefix=None,
                                                  context_path_prefix=None,
                                                  category=None)

        assert _testutil_get_param(config, 'api_key') is not None
        command = _testutil_get_command(config, 'test-report')
        assert command.headers == [{
            "Accept": "application/json"
        }, {
            "Content-Type": "application/json"
        }]
        assert config.auth == {
            "type":
            "apikey",
            "apikey": [{
                "key": "format",
                "value": "f'SSWS {params[\"api_key\"]}'",
                "type": "string"
            }, {
                "key": "in",
                "value": "header",
                "type": "string"
            }, {
                "key": "key",
                "value": "Authorization",
                "type": "string"
            }]
        }

        integration_code = config.generate_integration_python_code()

        assert "headers['Authorization'] = f'SSWS {params[\"api_key\"]}'" in integration_code

    def test_post_body_to_arguments(self, tmpdir):
        """
        If POST request requires data passed in the body, then command arguments should construct that data

        Given
        - postman collection
        - with POST request "test-create-group"
        - "test-create" requires data of the following structure
        {
            "test_name": "some name",
            "test_id": "some id",
            "test_filter": {
                "test_key": "this is nested object"
            }
        }

        When
        - creating config file

        Then
        - test-create command should contain arguments of "test_name" "test_id" "test_filter"

        When
        - generating code from the config file

        Then
        - "name", "id" and "filter" must be passed as request body
        - "name", "id" and "filter" should be arguments of "test-create-group" command in yml
        """
        path = Path(tmpdir, 'config.json')
        _testutil_create_postman_collection(
            dest_path=path,
            with_request={
                "name": "Test Create Group",
                "request": {
                    "method":
                    "POST",
                    "header": [{
                        "key": "Accept",
                        "value": "application/json"
                    }, {
                        "key": "Content-Type",
                        "value": "application/json"
                    }, {
                        "key": "Authorization",
                        "value": "SSWS {{apikey}}"
                    }],
                    "body": {
                        "mode":
                        "raw",
                        "raw":
                        """{"test_name":"some name","test_id":"some id","test_filter":{"test_key":"this is nested object"}}"""
                    },
                    "url": {
                        "raw": "{{url}}/api/v1/groups",
                        "host": ["{{url}}"],
                        "path": ["api", "v1", "groups"]
                    }
                },
                "response": []
            })

        config = postman_to_autogen_configuration(collection_path=path,
                                                  name=None,
                                                  command_prefix=None,
                                                  context_path_prefix=None,
                                                  category=None)

        command = _testutil_get_command(config, 'test-create-group')
        assert len(command.arguments) == 3
        assert command.arguments[0].name == 'test_name'
        assert command.arguments[0].in_ == 'body'
        assert not command.arguments[0].in_object

        assert command.arguments[1].name == 'test_id'
        assert command.arguments[1].in_ == 'body'
        assert not command.arguments[1].in_object

        assert command.arguments[2].name == 'test_key'
        assert command.arguments[2].in_ == 'body'
        assert command.arguments[2].in_object == ['test_filter']

        integration_code = config.generate_integration_python_code()
        integration_obj = config.generate_integration_yml()
        integration_yml = yaml.dump(integration_obj.to_dict())

        assert 'def test_create_group_request(self, test_name, test_id, test_key):' in integration_code
        assert 'data = {"test_filter": {"test_key": test_key}, "test_id": test_id, "test_name": test_name}' in integration_code
        assert 'response = self._http_request(\'POST\', \'api/v1/groups\', params=params, json_data=data, headers=headers)' in integration_code

        assert "name: test_id" in integration_yml
        assert "name: test_name" in integration_yml
        assert "name: test_key" in integration_yml

    def test_download_file(self):
        """
        Given
        - postman collection
        - with file-download request which has response with "_postman_previewlanguage": "raw"

        When
        - generating config file

        Then
        - ensure file-download request has "return_file": true

        When
        - generating integration

        Then
        - integration code, file_download_command should call fileResult function
        - integration yml, file-download should return File standard context outputs
        """
        pass
Пример #13
0
class TestOpenAPICodeGen:
    test_files_path = os.path.join(git_path(), 'demisto_sdk', 'tests',
                                   'test_files')
    swagger_path = os.path.join(test_files_path, 'swagger_pets.json')

    def init_integration(self, base_name: str = 'TestSwagger'):
        integration = OpenAPIIntegration(self.swagger_path,
                                         base_name,
                                         '-'.join(
                                             base_name.split(' ')).lower(),
                                         base_name.replace(' ', ''),
                                         unique_keys='id',
                                         root_objects='Pet',
                                         fix_code=True)

        integration.load_file()
        return integration

    def test_config_file(self, mocker):
        """
        Scenario: Generating an integration from a swagger file

        Given
            - A swagger file
        When
            - Generating the integration configuration file for the swagger file
        Then
            - Ensure the configuration file is generated correctly
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator,
                            'get_docker_image_latest_tag_request',
                            return_value='3.8.6.12176')

        integration = self.init_integration()
        integration.generate_configuration()

        with open(os.path.join(self.test_files_path, 'swagger_config.json'),
                  'rb') as config_path:
            config = json.load(config_path)

        assert json.dumps(integration.configuration) == json.dumps(config)

    def test_yaml_file(self, mocker):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
        When
           - Generating the integration yaml
        Then
           - Ensure the yaml file is generated correctly
       """

        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator,
                            'get_docker_image_latest_tag_request',
                            return_value='3.8.6.12176')
        integration = self.init_integration()

        with open(os.path.join(self.test_files_path, 'swagger_yaml.yml'),
                  'rb') as yaml_file:
            expected_yaml = yaml.load(yaml_file)

        yaml_obj = integration.generate_yaml().to_dict()

        assert yaml_obj == expected_yaml

    def test_python_file(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
        When
           - Generating the integration python code
        Then
           - Ensure the python file is generated correctly
       """
        integration = self.init_integration()

        with open(os.path.join(self.test_files_path, 'swagger_python.py'),
                  'r') as py_file:
            expected_py = py_file.read()

        py = integration.generate_python_code()
        assert py == expected_py

    def test_get_command_function(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file
        When
           - Generating a command function and a request function for a command
        Then
           - Ensure the commands are generated correctly
        """
        integration = self.init_integration()
        command = [
            c for c in integration.configuration['commands']
            if c['name'] == 'get-pet-by-id'
        ][0]

        command_function, req_function = integration.get_python_command_and_request_functions(
            command)

        assert command_function == expected_command_function
        assert req_function == expected_request_function

    def test_command_body_args(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file
        When
           - Generating arguments for the command request body
        Then
           - Ensure the arguments are generated correctly
        """
        from demisto_sdk.commands.openapi_codegen.openapi_codegen import \
            BASE_DATA
        integration = self.init_integration()
        command = [
            c for c in integration.configuration['commands']
            if c['name'] == 'create-user'
        ][0]

        expected_args = 'id=user_id, username=user_username, firstName=user_firstname, lastName=user_lastname,' \
                        ' email=user_email, password=user_password, phone=user_phone, userStatus=user_userstatus'

        arguments = integration.process_command_arguments(command)
        body_args = integration.format_params(arguments[3], BASE_DATA,
                                              BASE_DATA)
        assert expected_args == body_args

    def test_command_headers(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file
        When
           - Generating headers for the command request
        Then
           - Ensure the headers are generated correctly
        """
        integration = self.init_integration()
        command = [
            c for c in integration.configuration['commands']
            if c['name'] == 'post-pet-upload-image'
        ][0]

        expected_headers = [{'Content-Type': 'multipart/form-data'}]

        assert expected_headers == command['headers']

    def test_change_name_duplications(self):
        """
        Scenario: Generating an integration from a swagger file

        Given
           - A swagger file
           - A generated integration configuration file
           - Generated commands from the configuration file (added command with same summary but different path)
        When
           - Generating functions name.
        Then
           - Ensure that the names of given functions generated correctly.
        """

        integration = self.init_integration()
        assert [
            c for c in integration.configuration['commands']
            if c['name'] == 'post-pet-upload-image'
        ][0]
        assert [
            c for c in integration.configuration['commands']
            if c['name'] == 'post-pet-upload-image-by-uploadimage'
        ][0]

    def test_file_not_overwritten(self):
        """
        Given:
        - Configurations

        When:
        - Saving configuration file

        Then:
        - Ensure file does not overwrite given JSON file for open API code gen command.
        """
        integration = self.init_integration(base_name='swagger_pets')
        with open(self.swagger_path, 'r') as f:
            file_data_before_config_save = json.loads(f.read())
        integration.save_config(integration.configuration,
                                self.test_files_path)
        with open(self.swagger_path, 'r') as f:
            file_data_after_config_save = json.loads(f.read())
        assert file_data_after_config_save == file_data_before_config_save
        os.remove(
            os.path.join(self.test_files_path,
                         f'{integration.base_name}_config.json'))

    def test_ref_props_non_dict_handling(self):
        """
        Test added according to reported issue of 'str' object has no attribute 'items'.
        This test runs extract outputs commands with properties that are not dict, and expects to pass.

        Given:
        - Dict containing data.

        When:
        - Extracting outputs from the given data.

        Then:
        - Ensure extract outputs does not stop on 'str' object has no attribute 'items' error.
        """
        base_name = 'TestSwagger'
        integration = OpenAPIIntegration(self.swagger_path,
                                         base_name,
                                         '-'.join(
                                             base_name.split(' ')).lower(),
                                         base_name.replace(' ', ''),
                                         unique_keys='id',
                                         root_objects='Pet',
                                         fix_code=True)
        integration.reference = {
            'example': {
                'properties': 'type: object'
            },
            'example2': {
                'properties': {
                    'data': 2
                }
            }
        }
        data = {
            'responses': {
                '200': {
                    'description': 'Response number one',
                    'schema': [{
                        '$ref': '#/ref/example'
                    }]
                }
            }
        }
        integration.extract_outputs(data)
Пример #14
0
class TestPostmanCodeGen:
    test_files_path = os.path.join(git_path(), 'demisto_sdk', 'commands',
                                   'postman_codegen', 'tests', 'test_files')
    postman_collection_stream = None
    autogen_config_stream = None
    postman_collection: dict
    autogen_config: dict
    arguments_check_collection: dict

    @classmethod
    def setup_class(cls):
        collection_path = os.path.join(cls.test_files_path,
                                       'VirusTotal.postman_collection.json')
        autogen_config_path = os.path.join(cls.test_files_path,
                                           'VirusTotal-autogen-config.json')
        arguments_check_collection_path = os.path.join(
            cls.test_files_path, 'arguments_check_collection.json')
        with open(collection_path) as f:
            cls.postman_collection = json.load(f)

        with open(autogen_config_path) as f:
            cls.autogen_config = json.load(f)

        with open(arguments_check_collection_path) as f:
            cls.arguments_check_collection = json.load(f)

        cls.postman_collection_stream = open(collection_path)
        cls.autogen_config_stream = open(autogen_config_path)

    @classmethod
    def teardown_class(cls):
        cls.postman_collection_stream.close()
        cls.autogen_config_stream.close()

    @classmethod
    @pytest.fixture(autouse=True)
    def function_setup(cls):
        """
        Cleaning the content repo before every function
        """
        cls.postman_collection_stream.seek(0)
        cls.autogen_config_stream.seek(0)

    def test_config_generated_successfully(self, mocker):
        """
        This is general happy path test, the purpose of this test is not to test something specifically
        but to make sure if something changed in config file schema or broken, this test will fail because it is not
        identical with the actual result.
        If this test fails, validate that the reason for the failure is valid (like on purpose schema update) and then
        update the test file under resources folder.

        Given
        - Postman collection v2.1 of 4 Virus Total API commands

        When
        - generating config file from the postman collection

        Then
        - ensure the config file is generated
        - the config file should be identical to the one we have under resources folder
        """
        from demisto_sdk.commands.common.hook_validations.docker import \
            DockerImageValidator

        mocker.patch.object(DockerImageValidator,
                            'get_docker_image_latest_tag_request',
                            return_value='3.8.6.12176')

        autogen_config = postman_to_autogen_configuration(
            collection=self.postman_collection,
            name='VirusTotal Test',
            command_prefix='vt-test',
            context_path_prefix='VirusTotalTest')

        expected_config = json.load(self.autogen_config_stream)

        assert expected_config == autogen_config.to_dict()

    def test_command_prefix(self):
        """
        Given
        - postman collection with name Virus Total

        When
        - generating config file

        Then
        - ensure command_prefix is virustotal-

        """
        autogen_config = postman_to_autogen_configuration(
            collection=self.postman_collection,
            command_prefix=None,
            name=None,
            context_path_prefix=None,
            category=None)

        assert autogen_config.command_prefix == 'virustotal'

    def test_command_arguments_names_duplication(self):
        """
        Given
        - postman collection with one command, that has some arguments with the same name (suffix)

        When
        - generating config file

        Then
        - ensure the number of arguments generated is the same as the number of arguments in the command (if not, some arguments
        are generated as one with the same name)
        """
        autogen_config = postman_to_autogen_configuration(
            collection=self.arguments_check_collection,
            command_prefix=None,
            name=None,
            context_path_prefix=None,
            category=None)
        assert len(autogen_config.commands[0].arguments) == 15

    def test_context_output_path(self):
        """
        Given
        - postman collection with name Virus Total

        When
        - generating config file

        Then
        - ensure context_output_path of the whole integration is VirusTotal
        """
        autogen_config = postman_to_autogen_configuration(
            collection=self.postman_collection,
            context_path_prefix=None,
            command_prefix=None,
            name=None,
            category=None)

        assert autogen_config.context_path == 'VirusTotal'

    def test_url_contains_args(self, tmp_path):
        """
        Given
        - postman collection
        - with request Test Report which has variable {{foo}} in the url like:
        {{url}}/vtapi/v2/:Virus_name/test/{{foo}}?resource=https://www.cobaltstrike.com/

        When
        - generating config file

        Then
        - integration code, the command test-report will contain foo argument passed to the url
        - integration yml, the command test-report will contain foo arg
        - integration yml, the command test-report will contain virus_name arg.
        """
        path = tmp_path / 'test-collection.json'
        _testutil_create_postman_collection(
            dest_path=path,
            with_request={
                "name": "Test Report",
                "request": {
                    "method": "GET",
                    "header": [],
                    "url": {
                        "raw":
                        "{{url}}/vtapi/v2/:Virus_name/test/{{foo}}?resource=https://www.cobaltstrike.com/",
                        "host": ["{{url}}"],
                        "path":
                        ["vtapi", "v2", ":Virus_name", "test", "{{foo}}"],
                        "variable": [{
                            "key": "Virus_name",
                            "value": ""
                        }],
                        "query": [{
                            "key": "resource",
                            "value": "https://www.cobaltstrike.com/"
                        }]
                    },
                    "description": "Test Report description"
                }
            })

        config = postman_to_autogen_configuration(collection=json.load(
            open(path)),
                                                  name='VirusTotal',
                                                  context_path_prefix=None,
                                                  command_prefix=None)

        integration_code = config.generate_integration_python_code()
        integration_obj = config.generate_integration_yml()
        integration_yml = yaml.dumps(integration_obj.to_dict())

        assert "foo = args.get('foo')" in integration_code
        assert "virus_name = args.get('virus_name')" in integration_code
        assert "def test_report_request(self, foo, virus_name, resource):" in integration_code
        assert "'GET', f'vtapi/v2/{virus_name}/test/{foo}', params=params, headers=headers)" in integration_code

        assert 'name: foo' in integration_yml
        assert 'name: virus_name' in integration_yml

    def test_args_lowercase(self, tmp_path):
        """
        Given
        - Postman collection.
        - Test report request which has variables with upper case.

        When
        - Generating config file.

        Then
        - Integration code has arguments as lowercase, but sends the arguments to requests as given.
        - Integration yml, the arguments are lower case.
        """
        path = tmp_path / 'test-collection.json'
        _testutil_create_postman_collection(
            dest_path=path,
            with_request={
                "name": "Test Report",
                "request": {
                    "method": "GET",
                    "header": [],
                    "body": {
                        "mode": "raw",
                        "raw":
                        "{\n    \"A\": 2,\n    \"B\": 3,\n    \"c\": 4\n}"
                    },
                    "url": {
                        "raw":
                        "{{url}}/vtapi/v2/test/{{FOO_A}}?RESOURCE_B=https://www.cobaltstrike.com/",
                        "host": ["{{url}}"],
                        "path": ["vtapi", "v2", "test", "{{FOO_A}}"],
                        "query": [{
                            "key": "RESOURCE_B",
                            "value": "https://www.cobaltstrike.com/"
                        }]
                    },
                    "description": "Test Report description"
                }
            })

        config = postman_to_autogen_configuration(collection=json.load(
            open(path)),
                                                  name='VirusTotal',
                                                  context_path_prefix=None,
                                                  command_prefix=None)

        integration_code = config.generate_integration_python_code()
        integration_obj = config.generate_integration_yml()
        integration_yml = yaml.dumps(integration_obj.to_dict())

        assert "foo_a = args.get('foo_a')" in integration_code
        assert "def test_report_request(self, foo_a, resource_b, a, b, c)" in integration_code
        assert 'assign_params(RESOURCE_B=resource_b' in integration_code
        assert "('GET', f'vtapi/v2/test/{foo_a}', params=params, json_data=data, headers=headers)" in integration_code

        assert 'name: foo_a' in integration_yml
        assert 'name: resource_b' in integration_yml
        assert 'name: a\n' in integration_yml
        assert 'name: b\n' in integration_yml
        assert 'name: c\n' in integration_yml

    def test_apikey_passed_as_header(self, tmpdir):
        """
        Scenario: sometimes the auth method will not be defined under auth section, but as plain header Authorization

        Given
        - postman collection
        - with no auth defined
        - with request with headers:
            - "Authorization" header with value "SWSS {{apikey}}"
            - and other typical headers like Content-Type and Accept

        When
        - generating config file

        Then
        - config file should contain auth
        """
        path = Path(tmpdir, 'config.json')
        _testutil_create_postman_collection(dest_path=path,
                                            with_request={
                                                "name": "Test Report",
                                                "request": {
                                                    "method":
                                                    "GET",
                                                    "header": [{
                                                        "key":
                                                        "Accept",
                                                        "value":
                                                        "application/json"
                                                    }, {
                                                        "key":
                                                        "Content-Type",
                                                        "value":
                                                        "application/json"
                                                    }, {
                                                        "key":
                                                        "Authorization",
                                                        "value":
                                                        "SSWS {{apikey}}"
                                                    }],
                                                    "url": {
                                                        "raw": "{{url}}/test/",
                                                        "host": ["{{url}}"],
                                                        "path": [
                                                            "test",
                                                        ]
                                                    },
                                                    "description":
                                                    "Test Report description"
                                                }
                                            },
                                            no_auth=True)

        config = postman_to_autogen_configuration(collection=json.load(
            open(path)),
                                                  name=None,
                                                  command_prefix=None,
                                                  context_path_prefix=None,
                                                  category=None)

        assert _testutil_get_param(config, 'api_key') is not None
        command = _testutil_get_command(config, 'test-report')
        assert command.headers == [{
            "Accept": "application/json"
        }, {
            "Content-Type": "application/json"
        }]
        assert config.auth == {
            "type":
            "apikey",
            "apikey": [{
                "key": "format",
                "value": "f'SSWS {params[\"api_key\"]}'",
                "type": "string"
            }, {
                "key": "in",
                "value": "header",
                "type": "string"
            }, {
                "key": "key",
                "value": "Authorization",
                "type": "string"
            }]
        }

        integration_code = config.generate_integration_python_code()

        assert "headers['Authorization'] = f'SSWS {params[\"api_key\"]}'" in integration_code

    def test_post_body_to_arguments(self, tmpdir):
        """
        If POST request requires data passed in the body, then command arguments should construct that data

        Given
        - postman collection
        - with POST request "test-create-group"
        - "test-create" requires data of the following structure
        {
            "test_name": "some name",
            "test_id": "some id",
            "test_filter": {
                "test_key": "this is nested object"
            }
        }

        When
        - creating config file

        Then
        - test-create command should contain arguments of "test_name" "test_id" "test_filter"

        When
        - generating code from the config file

        Then
        - "name", "id" and "filter" must be passed as request body
        - "name", "id" and "filter" should be arguments of "test-create-group" command in yml
        """
        path = Path(tmpdir, 'config.json')
        _testutil_create_postman_collection(
            dest_path=path,
            with_request={
                "name": "Test Create Group",
                "request": {
                    "method":
                    "POST",
                    "header": [{
                        "key": "Accept",
                        "value": "application/json"
                    }, {
                        "key": "Content-Type",
                        "value": "application/json"
                    }, {
                        "key": "Authorization",
                        "value": "SSWS {{apikey}}"
                    }],
                    "body": {
                        "mode":
                        "raw",
                        "raw":
                        """{"test_name":"some name","test_id":"some id","test_filter":{"test_key":"this is nested object"}}"""
                    },
                    "url": {
                        "raw": "{{url}}/api/v1/groups",
                        "host": ["{{url}}"],
                        "path": ["api", "v1", "groups"]
                    }
                },
                "response": []
            })

        config = postman_to_autogen_configuration(collection=json.load(
            open(path)),
                                                  name=None,
                                                  command_prefix=None,
                                                  context_path_prefix=None,
                                                  category=None)

        command = _testutil_get_command(config, 'test-create-group')
        assert len(command.arguments) == 3
        assert command.arguments[0].name == 'test_name'
        assert command.arguments[0].in_ == 'body'
        assert not command.arguments[0].in_object

        assert command.arguments[1].name == 'test_id'
        assert command.arguments[1].in_ == 'body'
        assert not command.arguments[1].in_object

        assert command.arguments[2].name == 'test_key'
        assert command.arguments[2].in_ == 'body'
        assert command.arguments[2].in_object == ['test_filter']

        integration_code = config.generate_integration_python_code()
        integration_obj = config.generate_integration_yml()
        integration_yml = yaml.dumps(integration_obj.to_dict())

        assert 'def test_create_group_request(self, test_name, test_id, test_key):' in integration_code
        assert 'data = {"test_filter": {"test_key": test_key}, "test_id": test_id, "test_name": test_name}' in integration_code
        assert 'response = self._http_request(\'POST\', \'api/v1/groups\', params=params, json_data=data, headers=headers)' in integration_code

        assert "name: test_id" in integration_yml
        assert "name: test_name" in integration_yml
        assert "name: test_key" in integration_yml

    def test_download_file(self):
        """
        Given
        - postman collection
        - with file-download request which has response with "_postman_previewlanguage": "raw"

        When
        - generating config file

        Then
        - ensure file-download request has "return_file": true

        When
        - generating integration

        Then
        - integration code, file_download_command should call fileResult function
        - integration yml, file-download should return File standard context outputs
        """
        pass

    GENERATE_COMMAND_OUTPUTS_INPUTS = [
        ({
            'id': 1
        }, [IntegrationGeneratorOutput('id', '', 'Number')]),
        ([{
            'id': 1
        }], [IntegrationGeneratorOutput('id', '', 'Number')]),
        ([{
            'a': [{
                'b': 2
            }]
        }], [IntegrationGeneratorOutput('a.b', '', 'Number')])
    ]

    @pytest.mark.parametrize('body, expected', GENERATE_COMMAND_OUTPUTS_INPUTS)
    def test_generate_command_outputs(
            self, body: Union[List, Dict],
            expected: List[IntegrationGeneratorOutput]):
        """
        Given:
        - Body of postman generator command.

        When:
        - Building corresponding command for Cortex XSOAR.

        Then:
        - Ensure outputs are flattened correctly.
        """
        outputs: List[IntegrationGeneratorOutput] = generate_command_outputs(
            body)
        for i in range(len(outputs)):
            assert outputs[i].name == expected[i].name
            assert outputs[i].description == expected[i].description
            assert outputs[i].type_ == expected[i].type_
        assert len(outputs) == len(expected)

    def test_package_integration_generation(self, tmp_path):
        """
        Given
        - postman collection
        When
        - generating an integration in a package format
        Then
        - package should be created with the integration files.
        """
        package_path = os.path.join(self.test_files_path, 'package')
        os.mkdir(package_path)
        collection_path = os.path.join(self.test_files_path,
                                       'VirusTotal.postman_collection.json')
        try:
            runner = CliRunner()
            runner.invoke(main, [
                'postman-codegen', '-i', collection_path, '-o', package_path,
                '-p'
            ],
                          catch_exceptions=False)
            assert all(elem in os.listdir(package_path)
                       for elem in ['package.py', 'README.md', 'package.yml'])
        except Exception as e:
            raise e
        finally:
            shutil.rmtree(package_path)
Пример #15
0
class TestPostmanHelpers:
    def test_create_body_format(self):
        request_body = {
            "key1": "val1",
            "key2": {
                "key3": "val3"
            },
            "key4": [
                {
                    "key5": "val5"
                },
                {
                    "key5": "val51"
                },
            ],
            "key7": ["a", "b", "c"]
        }
        body_format = create_body_format(request_body)

        assert body_format == {
            "key1": "{key1}",
            "key2": {
                "key3": "{key3}"
            },
            "key4": [{
                "key5": "{key5}"
            }],
            "key7": "{key7}"
        }

    def test_create_body_format_list_of_dicts(self):
        request_body = [{"key1": "val1"}, {"key1": "val11"}]

        body_format = create_body_format(request_body)

        assert body_format == [{"key1": "{key1}"}]

    def test_create_body_format_different_arg_name_nested(self):
        """
        Given
        - Request body and a list of arguments.

        When
        - There are two arguments, both nested in other arguments, with the same name and different paths.

        Then
        - Creates a body format with the right arguments' names.
        """
        request_body = {
            "key5": {
                "key3": "val3"
            },
            "key2": {
                "key6": {
                    "key3": "val3",
                    "key8": "val8"
                }
            }
        }

        args: List[IntegrationGeneratorArg] = [
            IntegrationGeneratorArg(name="key5",
                                    description='',
                                    in_='body',
                                    in_object=[]),
            IntegrationGeneratorArg(name="key5_key3",
                                    description='',
                                    in_='body',
                                    in_object=["key5"]),
            IntegrationGeneratorArg(name="key2",
                                    description='',
                                    in_='body',
                                    in_object=[]),
            IntegrationGeneratorArg(name="key6",
                                    description='',
                                    in_='body',
                                    in_object=["key2"]),
            IntegrationGeneratorArg(name="key6_key3",
                                    description='',
                                    in_='body',
                                    in_object=["key2", "key6"]),
            IntegrationGeneratorArg(name="key8",
                                    description='',
                                    in_='body',
                                    in_object=["key2", "key6"]),
        ]
        body_format = create_body_format(request_body, args)

        assert body_format == {
            "key5": {
                "key3": "{key5_key3}"
            },
            "key2": {
                "key6": {
                    "key3": "{key6_key3}",
                    "key8": "{key8}"
                }
            }
        }

    def test_create_body_format_different_arg_name_one_nested(self):
        """
        Given
        - Request body and a list of arguments.

        When
        - There are two arguments, one of them nested in another argument, with the same name and different paths.

        Then
        - Creates a body format with the right arguments' names.
        """
        request_body = {"key1": "val1", "key4": [{"key1": "val5"}]}

        args: List[IntegrationGeneratorArg] = [
            IntegrationGeneratorArg(name="key1",
                                    description='',
                                    in_='body',
                                    in_object=[]),
            IntegrationGeneratorArg(name="key4",
                                    description='',
                                    in_='body',
                                    in_object=[]),
            IntegrationGeneratorArg(name="key4_key1",
                                    description='',
                                    in_='body',
                                    in_object=["key4"]),
        ]
        body_format = create_body_format(request_body, args)

        assert body_format == {
            "key1": "{key1}",
            "key4": [
                {
                    "key1": "{key4_key1}"
                },
            ],
        }

    @pytest.mark.parametrize('collection, outputs',
                             [([], []), ([[], []], []),
                              ([{}, [], [{}]], [{}, {}]),
                              ([{
                                  'item': [{}]
                              }, [], [{}]], [{}, {}])])
    def test_flatten_collections(self, collection: list, outputs: list):
        assert flatten_collections(collection) == outputs

    def test_build_commands_names_dict_duplicate_names(self):
        """
        Given
        - dictionary containing names of requests from a collection

        When
        - There are requests with names which have the same kebab case

        Then
        - returns names' dictionary with an entry of the matching kebab-case which has a list with the problematic names
        """
        requests = [{
            "name": "Test Number One"
        }, {
            "name": "Test number  one"
        }, {
            "name": "Test number two"
        }]
        names_dict = build_commands_names_dict(requests)
        assert len(names_dict[tools.to_kebab_case("Test Number One")]) == 2
        assert len(names_dict[tools.to_kebab_case("Test number two")]) == 1
        assert len(names_dict) == 2

    def test_build_commands_names_dict_no_duplicate_names(self):
        """
        Given
        - dictionary containing names of requests from a collection

        When
        - There are no requests with names which have the same kebab case

        Then
        - returns names' dictionary with an entry for each request's name kebab case and the original name
        """
        requests = [{"name": "Test Number One"}, {"name": "Test number two"}]
        names_dict = build_commands_names_dict(requests)
        assert len(names_dict[tools.to_kebab_case("Test Number One")]) == 1
        assert len(names_dict[tools.to_kebab_case("Test number two")]) == 1
        assert len(names_dict) == 2

    def test_build_commands_names_dict_none_names(self):
        """
        Given
        - dictionary containing names of requests from a collection

        When
        - There's a request with no name key

        Then
        - returns names' dictionary with an entry for each request's name kebab case and the original name and just them
        """
        requests = [{
            "None": None
        }, {
            "name": "Test number  one"
        }, {
            "name": "Test number two"
        }]
        names_dict = build_commands_names_dict(requests)
        assert len(names_dict[tools.to_kebab_case("Test Number One")]) == 1
        assert len(names_dict[tools.to_kebab_case("Test number two")]) == 1
        assert len(names_dict) == 2

    def test_duplicate_requests_check_duplicates_exist(self):
        """
        Given
        - dictionary containing names in kebab case of requests and a list with their original names

        When
        - There are requests with the same kebab case

        Then
        - throw assertion error with the problematic requests' names
        """
        with pytest.raises(Exception):
            names_dict = {
                'test-number-one': ["Test number  one", "Test Number One"],
                'test-number-two': ["Test number two"]
            }
            duplicate_requests_check(names_dict)

    def test_duplicate_requests_check_duplicates_dont_exist(self):
        """
        Given
        - dictionary containing names in kebab case of requests and a list with their original names

        When
        - There are no requests with the same kebab case

        Then
        - don't throw assertion error
        """
        names_dict = {
            'test-number-one': [
                "Test number  one",
            ],
            'test-number-two': ["Test number two"]
        }
        duplicate_requests_check(names_dict)

    test_files_path = os.path.join(git_path(), 'demisto_sdk', 'commands',
                                   'postman_codegen', 'tests', 'test_files')
    with open(os.path.join(test_files_path,
                           'shared_args_path.json')) as shared_args_path_file:
        shared_args_path_items = json.load(shared_args_path_file)

    many_with_shared_paths = defaultdict(int, {
        'name': 2,
        'description': 3,
        'url': 3,
        'method': 3
    })
    one_shared_for_each_paths = defaultdict(int, {
        'name': 1,
        'id': 1,
        'uid': 1
    })
    complicated_chars_in_paths = defaultdict(int, {'name': 1, 'required': 5})
    same_path_at_the_end = defaultdict(int, {'name': 2})
    SHARED_ARGS_PATH = ((shared_args_path_items['many_with_shared_paths'],
                         many_with_shared_paths),
                        (shared_args_path_items['one_shared_for_each_paths'],
                         one_shared_for_each_paths),
                        (shared_args_path_items['complicated_chars_in_paths'],
                         complicated_chars_in_paths),
                        (shared_args_path_items['same_path_at_the_end'],
                         same_path_at_the_end))

    @pytest.mark.parametrize(
        'flattened_json, shared_arg_to_split_position_dict', SHARED_ARGS_PATH)
    def test_find_shared_args_path(self, flattened_json,
                                   shared_arg_to_split_position_dict):
        """
        Given
        - Dictionary containing flattened json with raw body of a request

        When
        - There are arguments in the request which have the same name (suffix)

        Then
        - Returns arguments' dictionary with an entry for each argument name, that holds the minimum distinguishing shared path of
        all arguments with the same name
        """
        for arg_name, min_path_length in find_shared_args_path(
                flattened_json).items():
            assert shared_arg_to_split_position_dict[
                arg_name] == min_path_length

    def test_find_shared_args_path_no_path(self):
        """
        Given
        - Dictionary containing flattened json with raw body of a request, that doesn't have duplicate names

        When
        - There are no arguments in the request which have the same name (suffix)

        Then
        - Returns arguments' dictionary with an entry for each argument name, that holds the minimum distinguishing shared path of
        all arguments with the same name - which is 0 in this case
        """
        flattened_json = {
            "strategy": "deleteSource",
            "source": "{{source_collection_uid}}",
            "destination": "{{destination_collection_uid}}"
        }
        shared_arg_to_split_position_dict = defaultdict(int)
        for arg_name, min_path_length in find_shared_args_path(
                flattened_json).items():
            assert shared_arg_to_split_position_dict[
                arg_name] == min_path_length

    split_path1 = ['collection', 'item', 'settings', 'name']
    split_path2 = ['collection', 'info', 'settings', 'name']
    split_path3 = ['collection', 'item', 'property', 'name']
    split_path4 = ['set', 'item', 'property', 'name']

    first_call = (split_path2, [], 0, 0)
    max_to_bigger_then_zero = (split_path4, [split_path2], 0, 1)
    max_changes_on_first_item = (split_path4,
                                 [split_path3, split_path2, split_path1], 2, 3)
    max_changes_on_second_item = (split_path1, [split_path3,
                                                split_path2], 1, 2)
    max_doesnt_change = (split_path3, [split_path1, split_path2], 2, 2)
    UPDATED_MAX_INPUT = (first_call, max_to_bigger_then_zero,
                         max_changes_on_first_item, max_changes_on_second_item,
                         max_doesnt_change)

    @pytest.mark.parametrize(
        'split_path, other_args_split_paths, current_min_unique, new_min_unique',
        UPDATED_MAX_INPUT)
    def test_update_min_distinguish_path(self, split_path,
                                         other_args_split_paths,
                                         current_min_unique, new_min_unique):
        """
        Given
        - A split path of an argument, a list of other arguments' splitted paths, and the minimum unique path until now

        When
        - Finding the minimum unique path between the arguments that have the same name

        Then
        - Returns the minimum unique path of all arguments with the same name
        """
        assert update_min_unique_path(split_path, other_args_split_paths,
                                      current_min_unique) == new_min_unique
Пример #16
0
from os.path import join

import click
import pytest
from click.testing import CliRunner
from packaging.version import parse

from demisto_sdk.__main__ import main
from demisto_sdk.commands.common.legacy_git_tools import git_path

UPLOAD_CMD = "upload"
DEMISTO_SDK_PATH = join(git_path(), "demisto_sdk")


@pytest.fixture
def demisto_client(mocker):
    mocker.patch("demisto_sdk.commands.upload.uploader.demisto_client",
                 return_valure="object")
    mocker.patch("demisto_sdk.commands.upload.uploader.get_demisto_version",
                 return_value=parse('6.0.0'))
    mocker.patch(
        "demisto_sdk.commands.common.content.objects.pack_objects.integration.integration.get_demisto_version",
        return_value=parse('6.0.0'))
    mocker.patch(
        "demisto_sdk.commands.common.content.objects.pack_objects.script.script.get_demisto_version",
        return_value=parse('6.0.0'))
    mocker.patch("click.secho")


def test_integration_upload_pack_positive(demisto_client):
    """
Пример #17
0
class TestGenerateTestPlaybook:
    TEMP_DIR = 'temp'
    TEST_FILE_PATH = Path(git_path()) / 'demisto_sdk' / 'tests' / 'test_files'
    DUMMY_INTEGRATION_YML_PATH = TEST_FILE_PATH / 'fake_integration.yml'
    CREATED_DIRS = list()  # type: list

    @classmethod
    def setup_class(cls):
        print("Setups TestGenerateTestPlaybook class")
        Path(TestGenerateTestPlaybook.TEMP_DIR).mkdir(exist_ok=True)

    @classmethod
    def teardown_class(cls):
        print("Tearing down TestGenerateTestPlaybook class")
        if Path(TestGenerateTestPlaybook.TEMP_DIR).exists():
            shutil.rmtree(TestGenerateTestPlaybook.TEMP_DIR,
                          ignore_errors=False,
                          onerror=None)

    @pytest.mark.parametrize(
        "use_all_brands,expected_yml",
        [(False, 'fake_integration_expected_test_playbook.yml'),
         (True, 'fake_integration_expected_test_playbook__all_brands.yml')])
    def test_generate_test_playbook(self, use_all_brands, expected_yml):
        """
        Given:  An integration yml file
        When:   Calling generate_test_playbook with any value of use_all_brands
        Then:   Ensure output is in the expected format
        """
        generator = PlaybookTestsGenerator(
            input=TestGenerateTestPlaybook.DUMMY_INTEGRATION_YML_PATH,
            file_type='integration',
            output=TestGenerateTestPlaybook.TEMP_DIR,
            name='TestPlaybook',
            use_all_brands=use_all_brands)

        generator.run()
        excepted_path = TestGenerateTestPlaybook.TEST_FILE_PATH / expected_yml
        new_yml_path = Path(TestGenerateTestPlaybook.TEMP_DIR
                            ) / 'playbook-TestPlaybook_Test.yml'
        assert yaml.load(new_yml_path) == yaml.load(excepted_path)

    def test_generate_test_playbook__integration_under_packs(self, tmpdir):
        """
        Given:  An integration, inside the standard Content folder structure
        When:   Called `generate_test_playbook` without a blank `output` field
        Then:   Make sure the generated test playbook is correct, and saved in the standard location
                (.../Packs/<Pack name>/TestPlayBooks/playbook-<integration_name>_Test.yml)
        """
        pack_folder = Path(tmpdir) / 'Packs' / 'DummyPack'

        integration_folder = pack_folder / 'DummyIntegration'
        integration_folder.mkdir(parents=True)

        integration_path = integration_folder / 'DummyIntegration.yml'
        shutil.copy(TestGenerateTestPlaybook.DUMMY_INTEGRATION_YML_PATH,
                    integration_path)

        generator = PlaybookTestsGenerator(input=integration_path,
                                           file_type='integration',
                                           output="",
                                           name='TestPlaybook',
                                           use_all_brands=False)

        generator.run()

        expected_test_playbook_path = TestGenerateTestPlaybook.TEST_FILE_PATH / 'fake_integration_expected_test_playbook.yml'
        actual_test_playbook_path = pack_folder / 'TestPlaybooks' / 'playbook-TestPlaybook_Test.yml'
        assert yaml.load(actual_test_playbook_path) == yaml.load(
            expected_test_playbook_path)

    def test_generate_test_playbook__integration_not_under_packs(self):
        """
        Given: an integration, NOT inside the standard Content folder structure.
        When: called `generate_test_playbook`
        Then: Make sure the generated test playbook is correct, and saved in the folder from which SDK was called.
        """

        generator = PlaybookTestsGenerator(
            input=TestGenerateTestPlaybook.DUMMY_INTEGRATION_YML_PATH,
            file_type='integration',
            output="",
            name='TestPlaybook',
            use_all_brands=False)

        generator.run()

        expected_test_playbook_yml = get_yaml(
            str(
                Path(TestGenerateTestPlaybook.TEST_FILE_PATH /
                     'fake_integration_expected_test_playbook.yml')))
        actual_test_playbook_yml = get_yaml(
            str(Path('playbook-TestPlaybook_Test.yml')))

        assert expected_test_playbook_yml == actual_test_playbook_yml

    def test_generate_test_playbook__specified_output_folder(self, tmpdir):
        """
        Given: an integration yaml, and a specified output folder
        When: called `generate_test_playbook`
        Then: Make sure the generated test playbook is correct, and saved in the relevant location.
        """
        output = tmpdir / "some_folder"
        output.mkdir()
        generator = PlaybookTestsGenerator(
            input=TestGenerateTestPlaybook.DUMMY_INTEGRATION_YML_PATH,
            file_type='integration',
            output=output,
            name='TestPlaybook',
            use_all_brands=False)

        generator.run()

        expected_test_playbook_yml = get_yaml(
            TestGenerateTestPlaybook.TEST_FILE_PATH /
            'fake_integration_expected_test_playbook.yml')
        actual_test_playbook_yml = get_yaml(output /
                                            'playbook-TestPlaybook_Test.yml')

        assert expected_test_playbook_yml == actual_test_playbook_yml

    def test_generate_test_playbook__specified_output_file(self, tmpdir):
        """
        Given: an integration yaml, and a specified output file
        When: called `generate_test_playbook`
        Then: Make sure the generated test playbook is correct, and saved in the relevant location.
        """
        tmpdir.mkdir("some_folder")
        output = tmpdir.join("some_folder").join("dest_file.yml")

        generator = PlaybookTestsGenerator(
            input=TestGenerateTestPlaybook.DUMMY_INTEGRATION_YML_PATH,
            file_type='integration',
            output=output,
            name='TestPlaybook',
            use_all_brands=False)

        generator.run()

        expected_test_playbook_yml = get_yaml(
            Path(TestGenerateTestPlaybook.TEST_FILE_PATH /
                 'fake_integration_expected_test_playbook.yml'))
        actual_test_playbook_yml = get_yaml(output)

        assert expected_test_playbook_yml == actual_test_playbook_yml

    def test_generate_test_playbook__specified_non_yml_output_file(
            self, tmpdir):
        """
        Given: an integration yaml, and a specified output file that is NOT a yml file
        When: called `generate_test_playbook`
        Then: Make sure a relevant message is shown to user.
        """
        tmpdir.mkdir("some_folder")
        output = tmpdir.join("some_folder").join("dest_file.not_yml")

        with pytest.raises(PlaybookTestsGenerator.InvalidOutputPathError):
            generator = PlaybookTestsGenerator(
                input=TestGenerateTestPlaybook.DUMMY_INTEGRATION_YML_PATH,
                file_type='integration',
                output=output,
                name='TestPlaybook',
                use_all_brands=False)
            generator.run()