Lansweeper

The Lansweeper integration allows users to retrieve the asset details.

IT Services · Lansweeper

Details

IDLansweeper
ProviderInsight Partners
CategoryIT Services
From Version6.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

The Lansweeper integration allows users to retrieve the asset details.
This integration was integrated and tested with version 2.0 of Lansweeper

Configure Lansweeper in Cortex

Parameter Description Required
Application Identity Code Identity code generated for the specific application. True
Trust any certificate (not secure)   False
Use system proxy settings   False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

ls-site-list


Retrieve a list of all sites to which an application has access.

Base Command

ls-site-list

Input

There are no input arguments for this command.

Context Output

Path Type Description
Lansweeper.Site.id String Site ID.
Lansweeper.Site.name String Site name.

Command Example


#### Context Example

```json
{
    "Lansweeper": {
        "Site": [
            {
                "id": "401d153d-2a59-45eb-879a-c291390448ca",
                "name": "api-demo-data"
            },
            {
                "id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76",
                "name": "api-demo-data-v2"
            }
        ]
    }
}

Human Readable Output

Authorized Site(s)

Site ID Site Name
401d153d-2a59-45eb-879a-c291390448ca api-demo-data
56d4ed4f-b2ad-4587-91b5-07bd453c5c76 api-demo-data-v2

ls-ip-hunt


Return a list of all assets associated with a given site and IP address.

Base Command

ls-ip-hunt

Input

Argument Name Description Required
site_id Specify the site ID to retrieve the assets.

Note: To get site ID, execute ls-site-list command.
Optional
ip Specify the IP address to retrieve the specific asset.

Note: Supports multiple comma separated values.
Required
limit Number of records to retrieve in the response.

Note: The minimum value supported is 1 and maximum value supported is 500. Default is 50.
Optional

Context Output

Path Type Description
Lansweeper.IP.assetId String Asset ID.
Lansweeper.IP.assetBasicInfo.name String Asset name.
Lansweeper.IP.assetBasicInfo.domain String Domain the asset belongs to.
Lansweeper.IP.assetBasicInfo.description String Description of the asset.
Lansweeper.IP.assetBasicInfo.firstSeen Date Date and time at which the asset was first scanned.
Lansweeper.IP.assetBasicInfo.fqdn String FQDN of the asset.
Lansweeper.IP.assetBasicInfo.ipAddress String IP address associated with the asset.
Lansweeper.IP.assetBasicInfo.lastSeen Date Date and time at which the asset was last scanned.
Lansweeper.IP.assetBasicInfo.mac String Asset’s main MAC address.
Lansweeper.IP.assetBasicInfo.userName String Name of the last logged on user.
Lansweeper.IP.assetBasicInfo.type String Type of the asset.
Lansweeper.IP.assetBasicInfo.userDomain String Domain of the last logged on user.
Lansweeper.IP.assetCustom.sku String Asset’s SKU.
Lansweeper.IP.assetCustom.model String Model of the asset.
Lansweeper.IP.assetCustom.firmwareVersion String Firmware version, retrieved from plug and play devices via the UPnP, DNS-SD or SSDP protocol.
Lansweeper.IP.assetCustom.purchaseDate Date When the asset was purchased.
Lansweeper.IP.assetCustom.warrantyDate Date When the asset’s warranty expires.
Lansweeper.IP.assetCustom.comment String Comment on the asset..
Lansweeper.IP.assetCustom.location String Location of the asset.
Lansweeper.IP.assetCustom.contact String Contact person of the asset.
Lansweeper.IP.assetCustom.manufacturer String Manufacturer of the asset.
Lansweeper.IP.assetCustom.serialNumber String Serial number of the asset.
Lansweeper.IP.assetCustom.dnsName String DNS name of the asset.
Lansweeper.IP.assetCustom.stateName String State name of the asset.
Lansweeper.IP.operatingSystem.caption String Short description of the object. The string includes the operating system version.
Lansweeper.IP.operatingSystem.productType String Type of the operating system.
Lansweeper.IP.url String URL to the summary of the asset.
Lansweeper.IP.siteId String The ID of the site to which the asset belongs.
Lansweeper.IP.siteName String The name of the site to which the asset belongs.

Command Example

!ls-ip-hunt ip="192.168.2.1"

Context Example

{
    "Lansweeper": {
        "IP": [
            {
                "assetBasicInfo": {
                    "firstSeen": "2018-06-15T12:03:34.917Z",
                    "ipAddress": "192.168.2.1",
                    "lastSeen": "2018-07-19T14:45:58.793Z",
                    "mac": "02:0C:29:FE:A6:64",
                    "name": "192.168.2.1",
                    "type": "Network device"
                },
                "assetCustom": {
                    "stateName": "Active"
                },
                "assetId": "608fa4d61be3044511e7239e",
                "siteId": "401d153d-2a59-45eb-879a-c291390448ca",
                "siteName": "api-demo-data",
                "url": "https://app.lansweeper.com/api-demo-data/asset/MTI3My1Bc3NldC0wZGYzZGRiYS0zNzA3LTQ0ZWUtOWI0My1jMTkxOTQ1NmZkYTE=/summary"
            },
            {
                "assetBasicInfo": {
                    "firstSeen": "2018-06-15T10:02:34.917Z",
                    "ipAddress": "192.168.2.1",
                    "lastSeen": "2018-07-19T12:44:58.793Z",
                    "mac": "02:0C:29:FE:A6:64",
                    "name": "192.168.2.1",
                    "type": "Network device"
                },
                "assetCustom": {
                    "stateName": "Active"
                },
                "assetId": "60eed3ba8a037f9341893701",
                "siteId": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76",
                "siteName": "api-demo-data-v2",
                "url": "https://app.lansweeper.com/api-demo-data-v2/asset/MTI3My1Bc3NldC1mODdkZjg5MS1kNmVkLTQyYzgtYThmMS1jZDJmMTBlYmE1ZGU=/summary"
            }
        ]
    }
}

Human Readable Output

Asset(s)

Name Domain User Name User Domain FQDN Description Type IP Address Mac Address Model Manufacturer Serial Number SKU Site Name First Seen Last Seen
XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 192.168.2.1 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data 2018-02-12T16:04:02.733Z 2018-02-12T16:04:02.733Z
XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 192.168.2.1 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data-v2 2018-02-12T14:04:02.733Z 2021-08-10T14:18:20.913Z

ls-mac-hunt


Return a list of all assets associated with a given site and MAC address.

Base Command

ls-mac-hunt

Input

Argument Name Description Required
site_id Specify the site ID to retrieve the assets.

Note: To get site ID, execute ls-site-list command.
Optional
mac_address Specify the MAC address to retrieve the specific asset.

Note: Supports multiple comma separated values.
Required
limit Number of records to retrieve in the response.

Note: The minimum value supported is 1 and maximum value supported is 500. Default is 50.
Optional

Context Output

Path Type Description
Lansweeper.Mac.assetId String Asset ID.
Lansweeper.Mac.assetBasicInfo.name String Asset name.
Lansweeper.Mac.assetBasicInfo.domain String Domain the asset belongs to.
Lansweeper.Mac.assetBasicInfo.description String Description of the asset.
Lansweeper.Mac.assetBasicInfo.firstSeen Date Date and time at which the asset was first scanned.
Lansweeper.Mac.assetBasicInfo.fqdn String FQDN of the asset.
Lansweeper.Mac.assetBasicInfo.ipAddress String IP address associated with the asset.
Lansweeper.Mac.assetBasicInfo.lastSeen Date Date and time at which the asset was last scanned.
Lansweeper.Mac.assetBasicInfo.mac String Asset’s main MAC address.
Lansweeper.Mac.assetBasicInfo.userName String Name of the last logged on user.
Lansweeper.Mac.assetBasicInfo.type String Type of the asset.
Lansweeper.Mac.assetBasicInfo.userDomain String Domain of the last logged on user.
Lansweeper.Mac.assetCustom.sku String Asset’s SKU.
Lansweeper.Mac.assetCustom.model String Model of the asset.
Lansweeper.Mac.assetCustom.firmwareVersion String Firmware version, retrieved from plug and play devices via the UPnP, DNS-SD or SSDP protocol.
Lansweeper.Mac.assetCustom.purchaseDate Date When the asset was purchased.
Lansweeper.Mac.assetCustom.warrantyDate Date When the asset’s warranty expires.
Lansweeper.Mac.assetCustom.comment String Comment on the asset..
Lansweeper.Mac.assetCustom.location String Location of the asset.
Lansweeper.Mac.assetCustom.contact String Contact person of the asset.
Lansweeper.Mac.assetCustom.manufacturer String Manufacturer of the asset.
Lansweeper.Mac.assetCustom.serialNumber String Serial number of the asset.
Lansweeper.Mac.assetCustom.dnsName String DNS name of the asset.
Lansweeper.Mac.assetCustom.stateName String State name of the asset.
Lansweeper.Mac.operatingSystem.caption String Short description of the object. The string includes the operating system version.
Lansweeper.Mac.operatingSystem.productType String Type of the operating system.
Lansweeper.Mac.url String URL to the summary of the asset.
Lansweeper.Mac.siteId String The ID of the site to which the asset belongs.
Lansweeper.Mac.siteName String The name of the site to which the asset belongs.

Command Example

!ls-mac-hunt mac_address="03:00:00:00:00:57"

Context Example

{
    "Lansweeper": {
        "Mac": [
            {
                "assetBasicInfo": {
                    "domain": "Demo-domain",
                    "firstSeen": "2018-02-12T16:04:02.733Z",
                    "fqdn": "Demo67.com",
                    "ipAddress": "10.10.11.104",
                    "lastSeen": "2018-02-12T16:04:02.733Z",
                    "mac": "03:00:00:00:00:57",
                    "name": "XLAN-897",
                    "type": "APC",
                    "userDomain": "Demo-domain"
                },
                "assetCustom": {
                    "location": "Main Branch",
                    "purchaseDate": "2018-02-02T00:00:00.000Z",
                    "serialNumber": "LAN897",
                    "stateName": "Active",
                    "warrantyDate": "2023-02-02T00:00:00.000Z"
                },
                "assetId": "608fa4c81be3044511e6d97f",
                "siteId": "401d153d-2a59-45eb-879a-c291390448ca",
                "siteName": "api-demo-data",
                "url": "https://app.lansweeper.com/api-demo-data/asset/ODk3LUFzc2V0LTBkZjNkZGJhLTM3MDctNDRlZS05YjQzLWMxOTE5NDU2ZmRhMQ==/summary"
            },
            {
                "assetBasicInfo": {
                    "domain": "Demo-domain",
                    "firstSeen": "2018-02-12T14:04:02.733Z",
                    "fqdn": "Demo67.com",
                    "ipAddress": "10.10.11.104",
                    "lastSeen": "2021-08-10T14:18:20.913Z",
                    "mac": "03:00:00:00:00:57",
                    "name": "XLAN-897",
                    "type": "APC",
                    "userDomain": "Demo-domain"
                },
                "assetCustom": {
                    "location": "Main Branch",
                    "purchaseDate": "2018-02-02T02:00:00.000Z",
                    "serialNumber": "LAN897",
                    "stateName": "Active",
                    "warrantyDate": "2023-02-02T02:00:00.000Z"
                },
                "assetId": "60eed3b78a037f934189271c",
                "siteId": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76",
                "siteName": "api-demo-data-v2",
                "url": "https://app.lansweeper.com/api-demo-data-v2/asset/ODk3LUFzc2V0LWY4N2RmODkxLWQ2ZWQtNDJjOC1hOGYxLWNkMmYxMGViYTVkZQ==/summary"
            }
        ]
    }
}

Human Readable Output

Asset(s)

Name Domain User Name User Domain FQDN Description Type IP Address Mac Address Model Manufacturer Serial Number SKU Site Name First Seen Last Seen
XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 10.10.11.104 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data 2018-02-12T16:04:02.733Z 2018-02-12T16:04:02.733Z
XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 10.10.11.104 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data-v2 2018-02-12T14:04:02.733Z 2021-08-10T14:18:20.913Z

Configuration parameters

  • identity_code — Application Identity Code (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (3)

  • ls-ip-hunt

    Return a list of all assets associated with a given site and IP address.

  • ls-mac-hunt

    Return a list of all assets associated with a given site and MAC address.

  • ls-site-list

    Retrieve a list of all sites to which an application has access.

import json
import os
import time
from unittest.mock import patch

import pytest
from CommonServerPython import DemistoException, get_integration_context, set_integration_context
from Lansweeper import MESSAGES


def util_load_json(path):
    with open(path, encoding="utf-8") as f:
        return json.loads(f.read())


COMMON_GRAPHQL_ENDPOINT = "https://api.lansweeper.com/api/v2/graphql"
AUTHENTICATION_ENDPOINT = "https://api.lansweeper.com/api/integrations/oauth/token"
REDIRECT_URL = "https://mock.com"

MOCK_INTEGRATION_CONTEXT = {
    "access_token": "Bearer dummy",
    "valid_until": time.time() + 86400,
    "authorized_sites": [
        {"id": "401d153d-2a59-45eb-879a-c291390448ca", "name": "api-demo-data"},
        {"id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76", "name": "api-demo-data-v2"},
    ],
}

AUTHENTICATION_RESP_HEADER = {"access_token": "dummy", "token_type": "Bearer", "expires_in": 86400}


@pytest.fixture()
def client():
    from Lansweeper import Client

    return Client("", False, False, headers={"Authorization": "Token identity_code"})


def test_test_module_when_valid_response_is_returned(mocker):
    """
    To test test_module command when success response come.
    Given
        - A valid response
    When
        - The status code returned is 200
    Then
        - Ensure test module should return success
    """
    from Lansweeper import test_module

    mocked_client = mocker.Mock()
    mocked_client.http_request.return_value = {}
    assert test_module(mocked_client) == "ok"


@pytest.mark.parametrize(
    "status_code, error_msg",
    [
        (400, "Authentication error. Please provide valid 'Application Identity Code'."),
        (500, "The server encountered an internal error for Lansweeper and was unable to complete your request."),
    ],
)
def test_exception_handler(status_code, error_msg, mocker):
    """
    To test exception handler in various http error code.
    Given
        - a dictionary containing http code
    When
        - they are the error codes
    Then
        - raise DemistoException
    """
    from Lansweeper import Client

    mocked_response = mocker.Mock()
    mocked_response.status_code = status_code
    mocked_response.json.return_value = {}
    with pytest.raises(DemistoException) as err:
        Client.exception_handler(mocked_response)

    assert str(err.value) == error_msg


def test_lansweeper_site_list_command_when_valid_response_is_returned(mocker):
    """
    Test case scenario for successful execution of lnsw-site-list command.
    Given:
        - command arguments for list site command
    When:
        - Calling `lnsw-site-list` command
    Then:
        -  Returns the response data
    """
    from Lansweeper import lansweeper_site_list_command

    response = util_load_json(os.path.join("test_data", "site_list_command_response.json"))
    context = util_load_json(os.path.join("test_data", "site_list_command_context.json"))
    with open(os.path.join("test_data", "site_list_command_hr.md")) as f:
        readable_output = f.read()

    mocked_client = mocker.Mock()
    mocked_client.site_list.return_value = response

    command_response = lansweeper_site_list_command(mocked_client)

    assert command_response.outputs_prefix == "Lansweeper.Site"
    assert command_response.outputs_key_field == "id"
    assert command_response.outputs == context
    assert command_response.readable_output == readable_output


def test_main_unknown_commmand(mocker, monkeypatch, capfd):
    """
    Tests the execution of main function when unknown command name is provided
    Given:
        - unknown command
    When:
        - Calling `main` method
    Then:
        -  Raises exception
    """
    from Lansweeper import main

    monkeypatch.setattr(
        "demistomock.params",
        lambda: {
            "url": REDIRECT_URL,
            "credentials": {"identifier": "client_id", "password": "password"},
            "authorization_code": "123456",
        },
    )
    monkeypatch.setattr("demistomock.command", lambda: "unknown_command")

    mocked_client = mocker.Mock()
    mocked_client.http_request.return_value = {}

    with pytest.raises(SystemExit):
        capfd.close()
        main()


@patch("demistomock.getIntegrationContext")
def test_lansweeper_ip_hunt_command_when_valid_response_is_returned(mocker_get_context, mocker):
    """
    Test case scenario for successful execution of ls-ip-hunt command.
    Given:
        - command arguments for ip hunt command
    When:
        - Calling `ls-ip-hunt` command
    Then:
        -  Returns the response data
    """
    from Lansweeper import lansweeper_ip_hunt_command

    mocker_get_context.return_value = MOCK_INTEGRATION_CONTEXT
    response = util_load_json(os.path.join("test_data", "ip_hunt_command_response.json"))
    context = util_load_json(os.path.join("test_data", "ip_hunt_command_context.json"))
    with open(os.path.join("test_data", "ip_hunt_command_hr.md")) as f:
        readable_output = f.read()

    mocked_client = mocker.Mock()
    mocked_client.asset_list.return_value = response
    args = {"site_id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76", "ip": "127.0.0.1"}
    command_response = lansweeper_ip_hunt_command(mocked_client, args)

    assert command_response.outputs_prefix == "Lansweeper.IP"
    assert command_response.outputs_key_field == "assetId"
    assert command_response.outputs == context
    assert command_response.readable_output == readable_output


@patch("demistomock.getIntegrationContext")
def test_lansweeper_ip_hunt_command_when_empty_response_is_returned(mocker_get_context, mocker):
    """
    Test case scenario for successful execution of ls-ip-hunt command with an empty response.
    Given:
        - command arguments for hunt ip command
    When:
        - Calling `ls-ip-hunt` command
    Then:
        - Returns no records for the given input arguments
    """
    from Lansweeper import lansweeper_ip_hunt_command

    mocker_get_context.return_value = MOCK_INTEGRATION_CONTEXT
    response = {
        "data": {
            "site": {
                "assetResources": {
                    "total": 0,
                    "pagination": {"limit": 2, "current": None, "next": None, "page": "NEXT"},
                    "items": [],
                }
            }
        }
    }
    args = {"site_id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76", "ip": "127.0.0.1"}
    mocked_client = mocker.Mock()
    mocked_client.asset_list.return_value = response

    command_results = lansweeper_ip_hunt_command(mocked_client, args=args)

    assert command_results.readable_output == "### Asset(s)\n**No entries.**\n"


@pytest.mark.parametrize(
    "args,expected_error",
    [
        ({"site_id": "abc", "ip": ""}, MESSAGES["REQUIRED_ARGUMENT"].format("ip")),
        ({"site_id": "abc", "ip": "abc,1.1"}, MESSAGES["INVALID_IP"]),
        ({"ip": "127.0.0.1", "limit": 501}, MESSAGES["INVALID_LIMIT"].format("501")),
        ({"ip": "127.0.0.1", "limit": 0}, MESSAGES["INVALID_LIMIT"].format("0")),
    ],
)
@patch("demistomock.getIntegrationContext")
def test_lansweeper_ip_hunt_command_when_invalid_args_provided(mocker_get_context, client, args, expected_error):
    """
    Test case scenario when invalid arguments for ip hunt command are provided.
    Given:
        - invalid command arguments for ip hunt command
    When
        - Calling `ls-ip-hunt`
    Then:
        - Returns the response message of invalid input arguments
    """
    from Lansweeper import lansweeper_ip_hunt_command

    mocker_get_context.return_value = MOCK_INTEGRATION_CONTEXT
    with pytest.raises(ValueError) as err:
        lansweeper_ip_hunt_command(client, args)

    assert str(err.value) == expected_error


@patch("demistomock.getIntegrationContext")
def test_lansweeper_mac_hunt_command_when_valid_response_is_returned(mocker_get_context, mocker):
    """
    Test case scenario for successful execution of ls-mac-hunt command.
    Given:
        - command arguments for mac hunt command
    When:
        - Calling `ls-mac-hunt` command
    Then:
        -  Returns the response data
    """
    from Lansweeper import lansweeper_mac_hunt_command

    mocker_get_context.return_value = MOCK_INTEGRATION_CONTEXT
    response = util_load_json(os.path.join("test_data", "ip_hunt_command_response.json"))
    context = util_load_json(os.path.join("test_data", "mac_hunt_command_context.json"))
    with open(os.path.join("test_data", "ip_hunt_command_hr.md")) as f:
        readable_output = f.read()

    mocked_client = mocker.Mock()
    mocked_client.asset_list.return_value = response
    args = {"site_id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76", "mac_address": "00:0D:3A:2B:7E:B7"}
    command_response = lansweeper_mac_hunt_command(mocked_client, args)

    assert command_response.outputs_prefix == "Lansweeper.Mac"
    assert command_response.outputs_key_field == "assetId"
    assert command_response.outputs == context
    assert command_response.readable_output == readable_output


@patch("demistomock.getIntegrationContext")
def test_lansweeper_mac_hunt_command_when_empty_response_is_returned(mocker_get_context, mocker):
    """
    Test case scenario for successful execution of ls-mac-hunt command with an empty response.
    Given:
        - command arguments for hunt mac command
    When:
        - Calling `ls-mac-hunt` command
    Then:
        - Returns no records for the given input arguments
    """
    from Lansweeper import lansweeper_mac_hunt_command

    mocker_get_context.return_value = MOCK_INTEGRATION_CONTEXT
    response = {
        "data": {
            "site": {
                "assetResources": {
                    "total": 0,
                    "pagination": {"limit": 2, "current": None, "next": None, "page": "NEXT"},
                    "items": [],
                }
            }
        }
    }
    args = {"site_id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76", "mac_address": "00:0D:3A:2B:7E:B7"}
    mocked_client = mocker.Mock()
    mocked_client.asset_list.return_value = response

    command_results = lansweeper_mac_hunt_command(mocked_client, args=args)

    assert command_results.readable_output == "### Asset(s)\n**No entries.**\n"


@pytest.mark.parametrize(
    "args,expected_error",
    [
        ({"site_id": "abc", "mac_address": ""}, MESSAGES["REQUIRED_ARGUMENT"].format("mac_address")),
        ({"site_id": "abc", "mac_address": "abc,1.1"}, MESSAGES["INVALID_MAC"]),
        ({"mac_address": "02:0C:29:FE:A6:64", "limit": 501}, MESSAGES["INVALID_LIMIT"].format("501")),
        ({"mac_address": "02:0C:29:FE:A6:64", "limit": 0}, MESSAGES["INVALID_LIMIT"].format("0")),
    ],
)
@patch("demistomock.getIntegrationContext")
def test_lansweeper_mac_hunt_command_when_invalid_args_provided(mocker_get_context, client, args, expected_error):
    """
    Test case scenario when invalid arguments for mac hunt command are provided.
    Given:
        - invalid command arguments for mac hunt command
    When
        - Calling `ls-mac-hunt`
    Then:
        - Returns the response message of invalid input arguments
    """
    from Lansweeper import lansweeper_mac_hunt_command

    mocker_get_context.return_value = MOCK_INTEGRATION_CONTEXT
    with pytest.raises(ValueError) as err:
        lansweeper_mac_hunt_command(client, args)

    assert str(err.value) == expected_error


@pytest.mark.parametrize(
    "context,client_id,as_expected",
    [
        ({"identity_code": "dummy_id"}, "dummy_id", False),
        ({}, "dummy_id", True),
        ({"identity_code": ""}, "dummy_id", True),
        ({"identity_code": "other_dummy_code"}, "dummy_id", True),
    ],
)
def test_creds_changed(context, client_id, as_expected) -> None:
    """
    Scenario: To detect changes in credentials.
    When:
     - When user changes credentials (identity_code).
    Then:
     - Change in credentials should be detected correctly.
    """
    from Lansweeper import creds_changed

    set_integration_context(context)
    assert creds_changed(get_integration_context(), client_id) is as_expected


@pytest.mark.parametrize(
    "context",
    [
        {},
        {"dummy_key": "dummy_val"},
        {"dummy_key1": "dummy_val1", "dummy_key2": "dummy_val2"},
    ],
)
def test_invalidate_context(context) -> None:
    """
    Scenario: Demisto integration context should be invalidated if credentials are changed.
    Given:
     - User has provided new credentials.
    When:
     - When user changes credentials (identity_code).
    Then:
     - Integration context should be invalidated.
    """
    from Lansweeper import update_context

    set_integration_context(context)
    update_context("new_identity_code")
    assert get_integration_context() == {"identity_code": "new_identity_code"}