Skip to content

Commit

Permalink
Merge 5030edc into 34c20d6
Browse files Browse the repository at this point in the history
  • Loading branch information
RosenbergYehuda committed Feb 26, 2024
2 parents 34c20d6 + 5030edc commit aaab765
Show file tree
Hide file tree
Showing 3 changed files with 369 additions and 1 deletion.
301 changes: 300 additions & 1 deletion demisto_sdk/commands/validate/tests/BC_validators_test.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import pytest

from demisto_sdk.commands.common.constants import MarketplaceVersions
from demisto_sdk.commands.validate.tests.test_tools import (
REPO,
create_integration_object,
create_old_file_pointers,
create_metadata_object,
create_script_object,
)
from demisto_sdk.commands.validate.validators.BC_validators.BC100_breaking_backwards_subtype import (
BreakingBackwardsSubtypeValidator,
)
from demisto_sdk.commands.validate.validators.BC_validators.BC108_was_marketplace_modified import (
WasMarketplaceModifiedValidator,
)
from TestSuite.repo import ChangeCWD

ALL_MARKETPLACES = list(MarketplaceVersions)
XSIAM_MARKETPLACE = [ALL_MARKETPLACES[1]]
ALL_MARKETPLACES_FOR_IN_PACK = [marketplace.value for marketplace in ALL_MARKETPLACES]
XSIAM_MARKETPLACE_FOR_IN_PACK = [ALL_MARKETPLACES_FOR_IN_PACK[1]]
XSOAR_MARKETPLACE = [ALL_MARKETPLACES[0]]
XSOAR_MARKETPLACE_FOR_IN_PACK = [ALL_MARKETPLACES_FOR_IN_PACK[0]]


@pytest.mark.parametrize(
Expand Down Expand Up @@ -117,3 +130,289 @@ def test_BreakingBackwardsSubtypeValidator_fix(
validator.old_subtype[content_item.name] = "python3"
assert validator.fix(content_item).message == expected_fix_msg
assert content_item.subtype == expected_subtype


@pytest.mark.parametrize(
"old_marketplaces, in_pack_marketplaces",
[
(ALL_MARKETPLACES, XSIAM_MARKETPLACE_FOR_IN_PACK),
(XSIAM_MARKETPLACE, ALL_MARKETPLACES_FOR_IN_PACK),
(XSIAM_MARKETPLACE, XSIAM_MARKETPLACE_FOR_IN_PACK),
],
)
def test_WasMarketplaceModifiedValidator__modified_item_has_only_one_marketplace__passes(
old_marketplaces, in_pack_marketplaces
):
"""
Given:
- Modified `Integration` and `Script` and Old `Integration` and `Script` iterables, each within a pack.
- Modified `Integration` and `Script` have only `XSIAM` in their level.
- Case 1: Old `Integration` and `Script` have all marketplaces in their level, and the pack has only `XSIAM`.
- Case 2: Old `Integration` and `Script` have only `XSIAM`, and the pack has all marketplaces.
- Case 3: Old `Integration` and `Script` have only `XSIAM`, and the pack has only one marketplace (`XSIAM`).
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Case 1: Should pass the validation since although the user defined only `XSIAM`, the content item will be used only in the `XSIAM` marketplace as defined in the pack level.
- Case 2: Should pass the validation since the user did not remove any marketplace.
- Case 3: Should pass the validation since the user did not remove any marketplace.
"""
modified_content_items = [
create_integration_object(pack_info={"marketplaces": in_pack_marketplaces}),
create_script_object(pack_info={"marketplaces": in_pack_marketplaces}),
]
old_content_items = [create_integration_object(), create_script_object()]

modified_content_items[0].marketplaces = modified_content_items[1].marketplaces = (
XSIAM_MARKETPLACE
)
old_content_items[0].marketplaces = old_content_items[1].marketplaces = (
old_marketplaces
)
create_old_file_pointers(modified_content_items, old_content_items)

with ChangeCWD(REPO.path):
assert WasMarketplaceModifiedValidator().is_valid(modified_content_items) == []


@pytest.mark.parametrize(
"old_marketplaces, in_pack_marketplaces",
[
(ALL_MARKETPLACES, ALL_MARKETPLACES_FOR_IN_PACK),
(XSOAR_MARKETPLACE, ALL_MARKETPLACES_FOR_IN_PACK),
],
)
def test_WasMarketplaceModifiedValidator__modified_item_has_only_one_marketplace__fails(
old_marketplaces, in_pack_marketplaces
):
"""
Given:
- Modified `Integration` and `Script` and Old `Integration` and `Script` iterables, each within a pack.
- Modified `Integration` and `Script` have only `XSIAM` in their level.
- Case 1: Old `Integration` and `Script` have all marketplaces in their level, and the pack has all marketplaces.
- Case 2: Old `Integration` and `Script` have only `XSOAR`, and the pack has all marketplaces.
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Case 1: Should fail the validation since the user removed marketplaces.
- Case 2: Should fail the validation since the user replaced one marketplace with a different one.
"""
modified_content_items = [
create_integration_object(pack_info={"marketplaces": in_pack_marketplaces}),
create_script_object(pack_info={"marketplaces": in_pack_marketplaces}),
]
old_content_items = [create_integration_object(), create_script_object()]

modified_content_items[0].marketplaces = modified_content_items[1].marketplaces = (
XSIAM_MARKETPLACE
)
old_content_items[0].marketplaces = old_content_items[1].marketplaces = (
old_marketplaces
)
create_old_file_pointers(modified_content_items, old_content_items)

with ChangeCWD(REPO.path):
results = WasMarketplaceModifiedValidator().is_valid(modified_content_items)
assert (
results[0].message
== "You can't add new marketplaces if they'll remove existing ones, or delete current marketplace content. Please undo the change or ask for a forced merge."
)
assert len(results) == 2


@pytest.mark.parametrize(
"modified_marketplaces, in_pack_marketplaces",
[
(ALL_MARKETPLACES, XSIAM_MARKETPLACE_FOR_IN_PACK),
(ALL_MARKETPLACES, ALL_MARKETPLACES_FOR_IN_PACK),
],
)
def test_WasMarketplaceModifiedValidator__old_item_has_only_one_marketplace__passes(
modified_marketplaces, in_pack_marketplaces
):
"""
Given:
- Modified `Integration` and `Script` and Old `Integration` and `Script` iterables, each within a pack.
- Old `Integration` and `Script` have only `XSIAM` in their level.
- Case 1: Modified `Integration` and `Script` have all marketplaces in their level, and the pack has only `XSIAM`.
- Case 2: Modified `Integration` and `Script` have all marketplaces in their level, and the pack has all marketplaces.
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Case 1: Should pass the validation since the user added marketplaces or removed all marketplaces which is equal to adding all marketplaces.
- Case 2: Should pass the validation since the user added marketplaces or removed all marketplaces which is equal to adding all marketplaces.
"""
modified_content_items = [
create_integration_object(pack_info={"marketplaces": in_pack_marketplaces}),
create_script_object(pack_info={"marketplaces": in_pack_marketplaces}),
]
old_content_items = [create_integration_object(), create_script_object()]

modified_content_items[0].marketplaces = modified_content_items[1].marketplaces = (
modified_marketplaces
)
old_content_items[0].marketplaces = old_content_items[1].marketplaces = (
XSIAM_MARKETPLACE
)
create_old_file_pointers(modified_content_items, old_content_items)

with ChangeCWD(REPO.path):
assert WasMarketplaceModifiedValidator().is_valid(modified_content_items) == []


def test_WasMarketplaceModifiedValidator__old_item_has_only_one_marketplace__fails():
"""
Given:
- Modified `Integration` and `Script` and Old `Integration` and `Script` iterables, each within a pack.
- Old `Integration` and `Script` have only `XSIAM` in their level.
- Modified `Integration` and `Script` have only `XSOAR`, and the pack has all marketplaces.
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Should fail the validation since the user replaced one marketplace with a different one.
"""
modified_marketplaces = XSOAR_MARKETPLACE
in_pack_marketplaces = ALL_MARKETPLACES_FOR_IN_PACK

modified_content_items = [
create_integration_object(pack_info={"marketplaces": in_pack_marketplaces}),
create_script_object(pack_info={"marketplaces": in_pack_marketplaces}),
]
old_content_items = [create_integration_object(), create_script_object()]

modified_content_items[0].marketplaces = modified_content_items[1].marketplaces = (
modified_marketplaces
)
old_content_items[0].marketplaces = old_content_items[1].marketplaces = (
XSIAM_MARKETPLACE
)
create_old_file_pointers(modified_content_items, old_content_items)

with ChangeCWD(REPO.path):
results = WasMarketplaceModifiedValidator().is_valid(modified_content_items)
assert (
results[0].message
== "You can't add new marketplaces if they'll remove existing ones, or delete current marketplace content. Please undo the change or ask for a forced merge."
)
assert len(results) == 2


@pytest.mark.parametrize(
"in_pack_marketplaces",
[
(XSIAM_MARKETPLACE_FOR_IN_PACK),
(ALL_MARKETPLACES_FOR_IN_PACK),
],
)
def test_WasMarketplaceModifiedValidator__old_and_modified_items_have_all_marketplace(
in_pack_marketplaces,
):
"""
Given:
- Modified `Integration` and `Script` and Old `Integration` and `Script` iterables, each within a pack.
- Modified `Integration` and `Script` have all marketplaces in their level.
- Old `Integration` and `Script` have all marketplaces in their level.
- Case 1: Pack has only `XSIAM`.
- Case 2: Pack has all marketplaces.
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Case 1: Should pass the validation since the user added marketplaces or removed all marketplaces which is equal to adding all marketplaces.
- Case 2: Should pass the validation since the user didn't change anything or removed all marketplaces which is equal to adding all marketplaces.
"""

modified_content_items = [
create_integration_object(pack_info={"marketplaces": in_pack_marketplaces}),
create_script_object(pack_info={"marketplaces": in_pack_marketplaces}),
]
old_content_items = [create_integration_object(), create_script_object()]

create_old_file_pointers(modified_content_items, old_content_items)
with ChangeCWD(REPO.path):
assert WasMarketplaceModifiedValidator().is_valid(modified_content_items) == []


@pytest.mark.parametrize(
"modified_pack, old_pack",
[
(ALL_MARKETPLACES, ALL_MARKETPLACES),
(ALL_MARKETPLACES, XSIAM_MARKETPLACE),
(XSIAM_MARKETPLACE, XSIAM_MARKETPLACE),
],
)
def test_WasMarketplaceModifiedValidator__a_pack_is_modified__passes(
modified_pack, old_pack
):
"""
Given:
- Modified `Pack` and Old `Pack` iterables.
- Case 1: Modified `Pack` and Old `Pack` have all marketplaces.
- Case 2: Modified `Pack` has all marketplaces and Old `Pack` has only `XSIAM`.
- Case 3: Modified `Pack` and Old `Pack` have only `XSIAM`.
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Case 1: Should pass the validation since the user didn't change anything or removed all marketplaces which is equal to adding all marketplaces.
- Case 2: Should pass the validation since the user added marketplaces or removed all marketplaces which is equal to adding all marketplaces.
- Case 3: Should pass the validation since the user didn't change anything or removed all marketplaces which is equal to adding all marketplaces.
"""
modified_content_item = [create_metadata_object()]
old_content_item = [create_metadata_object()]
modified_content_item[0].marketplaces = modified_pack
old_content_item[0].marketplaces = old_pack

create_old_file_pointers(modified_content_item, old_content_item)
assert WasMarketplaceModifiedValidator().is_valid(modified_content_item) == []


@pytest.mark.parametrize(
"modified_pack, old_pack",
[(XSIAM_MARKETPLACE, ALL_MARKETPLACES), (XSIAM_MARKETPLACE, XSOAR_MARKETPLACE)],
)
def test_WasMarketplaceModifiedValidator__a_pack_is_modified__fails(
modified_pack, old_pack
):
"""
Given:
- Modified `Pack` and Old `Pack` iterables.
- Case 1: Modified `Pack` has only `XSIAM` and Old `Pack` has all marketplaces.
- Case 2: Modified `Pack` has only `XSIAM` and Old `Pack` has only `XSOAR`.
When:
- Calling the `WasMarketplaceModifiedValidator` function.
Then:
- The results should be as expected.
- Case 1: Should fail the validation since the user removed marketplaces.
- Case 2: Should fail the validation since the user replaced one marketplace with a different one.
"""
modified_content_item = [create_metadata_object()]
old_content_item = [create_metadata_object()]
modified_content_item[0].marketplaces = modified_pack
old_content_item[0].marketplaces = old_pack

create_old_file_pointers(modified_content_item, old_content_item)
results = WasMarketplaceModifiedValidator().is_valid(modified_content_item)
assert (
results[0].message
== "You can't add new marketplaces if they'll remove existing ones, or delete current marketplace content. Please undo the change or ask for a forced merge."
)
1 change: 1 addition & 0 deletions demisto_sdk/commands/validate/tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from demisto_sdk.commands.common.tools import set_value
from demisto_sdk.commands.content_graph.objects.base_content import BaseContent
from demisto_sdk.commands.content_graph.objects.integration import Integration
from demisto_sdk.commands.content_graph.objects.pack import Pack
from demisto_sdk.commands.content_graph.objects.pack_metadata import PackMetadata
from demisto_sdk.commands.content_graph.objects.parsing_rule import ParsingRule
from demisto_sdk.commands.content_graph.objects.playbook import Playbook
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from __future__ import annotations

from typing import Iterable, List, Union

from demisto_sdk.commands.common.constants import GitStatuses, MarketplaceVersions
from demisto_sdk.commands.content_graph.objects.integration import Integration
from demisto_sdk.commands.content_graph.objects.script import Script
from demisto_sdk.commands.content_graph.objects.incident_type import IncidentType
from demisto_sdk.commands.content_graph.objects.mapper import Mapper
from demisto_sdk.commands.content_graph.objects.indicator_field import IndicatorField
from demisto_sdk.commands.content_graph.objects.indicator_type import IndicatorType
from demisto_sdk.commands.content_graph.objects.incident_field import IncidentField
from demisto_sdk.commands.content_graph.objects import Pack
from demisto_sdk.commands.content_graph.objects import Playbook
from demisto_sdk.commands.validate.validators.base_validator import (
BaseValidator,
ValidationResult,
)

ContentTypes = Union[
Integration,
Script,
IncidentType,
Mapper,
IndicatorField,
IndicatorType,
IncidentField,
Pack,
Playbook,
]
ALL_MARKETPLACES = list(MarketplaceVersions)


class WasMarketplaceModifiedValidator(BaseValidator[ContentTypes]):
error_code = "BC108"
description = "Ensuring that the 'marketplaces' property hasn't been removed or added in a manner that effectively removes all others."
error_message = "You can't add new marketplaces if they'll remove existing ones, or delete current marketplace content. Please undo the change or ask for a forced merge."
fix_message = ""
related_field = "marketplaces"
is_auto_fixable = False
expected_git_statuses = [GitStatuses.MODIFIED]

def is_valid(self, content_items: Iterable[ContentTypes]) -> List[ValidationResult]:
results: List[ValidationResult] = []
for content_item in content_items:

new_marketplaces = content_item.marketplaces
old_marketplaces = content_item.old_base_content_object.marketplaces # type: ignore

# if the content is not a pack, we may want to compare to the pack marketplaces as well, since the item inherits the pack marketplaces, if not specified
if not isinstance(content_item, Pack):
pack_marketplaces = content_item.in_pack.marketplaces # type: ignore

# If all marketplaces are included, it might be due to the field not appearing. However, in reality, it is available only in a specific marketplace inherited from the pack marketplace.
# In this scenario, we will compare the pack's marketplaces as it serves as the source of truth.
if set(old_marketplaces) == set(ALL_MARKETPLACES):
old_marketplaces = pack_marketplaces

if not (set(old_marketplaces).issubset(set(new_marketplaces))):
results.append(
ValidationResult(
validator=self,
message=self.error_message,
content_object=content_item,
)
)

return results

0 comments on commit aaab765

Please sign in to comment.