From 7c572da382bdd20159913cda81c9ad833019a483 Mon Sep 17 00:00:00 2001 From: William Bergamin Date: Tue, 21 Oct 2025 13:57:56 -0400 Subject: [PATCH 1/3] feat: improve template behavior --- listeners/filters.py | 40 +++++ listeners/functions/filters.py | 61 +++----- listeners/functions/search.py | 29 ++-- listeners/sample_data_service.py | 36 +++-- tests/listeners/functions/test_filters.py | 33 ++-- tests/listeners/functions/test_search.py | 68 ++++++--- tests/listeners/test_sample_data_service.py | 159 ++++++++++++++++++++ 7 files changed, 322 insertions(+), 104 deletions(-) create mode 100644 listeners/filters.py create mode 100644 tests/listeners/test_sample_data_service.py diff --git a/listeners/filters.py b/listeners/filters.py new file mode 100644 index 0000000..55c705b --- /dev/null +++ b/listeners/filters.py @@ -0,0 +1,40 @@ +from dataclasses import dataclass +from enum import Enum +from typing import List, Optional + + +class FilterType(Enum): + MULTI_SELECT = "multi_select" + TOGGLE = "toggle" + + +@dataclass +class FilterOptions: + name: str + value: str + + +@dataclass +class Filter: + name: str + display_name: str + type: FilterType + options: Optional[List[FilterOptions]] = None + + +LANGUAGES_FILTER = Filter( + name="languages", + display_name="Languages", + type=FilterType.MULTI_SELECT.value, + options=[ + FilterOptions(name="Python", value="python"), + FilterOptions(name="Java", value="java"), + FilterOptions(name="JavaScript", value="javascript"), + FilterOptions(name="TypeScript", value="typescript"), + ], +) + +TEMPLATES_FILTER = Filter(name="template", display_name="Templates", type=FilterType.TOGGLE.value) + + +SAMPLES_FILTER = Filter(name="sample", display_name="Samples", type=FilterType.TOGGLE.value) diff --git a/listeners/functions/filters.py b/listeners/functions/filters.py index 674a3a6..87fe26a 100644 --- a/listeners/functions/filters.py +++ b/listeners/functions/filters.py @@ -1,62 +1,35 @@ import logging -from enum import Enum -from typing import List, Optional, TypedDict +from dataclasses import asdict from slack_bolt import Ack, Complete, Fail +from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER, TEMPLATES_FILTER + FILTER_PROCESSING_ERROR_MSG = ( "We encountered an issue processing filter results. Please try again or contact the app owner if the problem persists." ) - -class FilterType(Enum): - MULTI_SELECT = "multi_select" - TOGGLE = "toggle" - - -class FilterOptions(TypedDict): - name: str - value: str - - -class SearchFilter(TypedDict): - name: str - display_name: str - filter_type: FilterType - options: Optional[List[FilterOptions]] - +filter_none = lambda items: {k: v for k, v in items if v is not None} def filters_step_callback(ack: Ack, inputs: dict, fail: Fail, complete: Complete, logger: logging.Logger): try: user_context = inputs.get("user_context", {}) logger.debug(f"User {user_context.get('id')} executing filter request") - filters: List[SearchFilter] = [ - { - "name": "languages", - "display_name": "Languages", - "type": FilterType.MULTI_SELECT.value, - "options": [ - {"name": "Python", "value": "python"}, - {"name": "Java", "value": "java"}, - {"name": "JavaScript", "value": "javascript"}, - {"name": "TypeScript", "value": "typescript"}, - ], - }, - { - "name": "type", - "display_name": "Type", - "type": FilterType.MULTI_SELECT.value, - "options": [ - {"name": "Template", "value": "template"}, - {"name": "Sample", "value": "sample"}, - ], - }, - ] - - complete(outputs={"filters": filters}) + complete( + outputs={ + "filters": [ + asdict(LANGUAGES_FILTER, dict_factory=filter_none), + asdict(TEMPLATES_FILTER, dict_factory=filter_none), + asdict(SAMPLES_FILTER, dict_factory=filter_none), + ] + } + ) except Exception as e: - logger.error(f"Unexpected error occurred while processing filter request: {type(e).__name__} - {str(e)}", exc_info=e) + logger.error( + f"Unexpected error occurred while processing filter request: {type(e).__name__} - {str(e)}", + exc_info=e, + ) fail(error=FILTER_PROCESSING_ERROR_MSG) finally: ack() diff --git a/listeners/functions/search.py b/listeners/functions/search.py index c0af4d7..eab2406 100644 --- a/listeners/functions/search.py +++ b/listeners/functions/search.py @@ -1,10 +1,10 @@ import logging -from ast import List -from typing import NotRequired, Optional, TypedDict +from typing import List, NotRequired, Optional, TypedDict from slack_bolt import Ack, Complete, Fail from slack_sdk import WebClient +from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER from listeners.sample_data_service import SlackResponseError, fetch_sample_data SEARCH_PROCESSING_ERROR_MSG = ( @@ -29,21 +29,19 @@ class SearchResult(TypedDict): content: NotRequired[str] -def search_step_callback(ack: Ack, inputs: dict, fail: Fail, complete: Complete, client: WebClient, logger: logging.Logger): +def search_step_callback( + ack: Ack, + inputs: dict, + fail: Fail, + complete: Complete, + client: WebClient, + logger: logging.Logger, +): try: query = inputs.get("query") - filters = inputs.get("filters", {}) - languages_filter = filters.get("languages", []) - type_filter = filters.get("type", []) + filters = inputs.get("filters") - filters_payload = {} - if languages_filter: - filters_payload["languages"] = languages_filter - if type_filter: - if len(type_filter) == 1: - filters_payload["type"] = type_filter[0] - - response = fetch_sample_data(client=client, query=query, filters=filters_payload, logger=logger) + response = fetch_sample_data(client=client, query=query, filters=filters, logger=logger) samples = response.get("samples", []) @@ -66,7 +64,8 @@ def search_step_callback(ack: Ack, inputs: dict, fail: Fail, complete: Complete, fail(error=SEARCH_PROCESSING_ERROR_MSG) else: logger.error( - f"Unexpected error occurred while processing search request: {type(e).__name__} - {str(e)}", exc_info=e + f"Unexpected error occurred while processing search request: {type(e).__name__} - {str(e)}", + exc_info=e, ) finally: ack() diff --git a/listeners/sample_data_service.py b/listeners/sample_data_service.py index 54b3f3b..65eb1b2 100644 --- a/listeners/sample_data_service.py +++ b/listeners/sample_data_service.py @@ -3,6 +3,10 @@ from slack_sdk import WebClient +from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER, TEMPLATES_FILTER + +API_METHOD = "developer.sampleData.get" + class SlackResponseError(Exception): def __init__(self, message: str): @@ -11,21 +15,31 @@ def __init__(self, message: str): def fetch_sample_data(client: WebClient, query: str = None, filters: dict = None, logger: logging.Logger = None): - method = "developer.sampleData.get" - params = {} - if query: - params["query"] = query + params = {"query": query} + if filters: - params["filters"] = json.dumps(filters) + selected_filters = {} + + languages = filters.get(LANGUAGES_FILTER.name, []) + templates = filters.get(TEMPLATES_FILTER.name, False) + samples = filters.get(SAMPLES_FILTER.name, False) - response = client.api_call(method, params=params) + if languages: + selected_filters[LANGUAGES_FILTER.name] = languages + + if templates ^ samples: + if templates: + selected_filters["type"] = TEMPLATES_FILTER.name + elif samples: + selected_filters["type"] = SAMPLES_FILTER.name + + if selected_filters: + params["filters"] = selected_filters + + response = client.api_call(API_METHOD, params=params) if not response.get("ok", False): logger.error(f"Search API request failed with error: {response.get('error', 'no error found')}") - raise SlackResponseError(f"Failed to fetch sample data from Slack API: ok=false for method={method}") - - if "samples" not in response: - logger.error(f"Failed to parse API response as sample data. Received: {json.dumps(response)}") - raise SlackResponseError(f"Invalid response format from Slack API from {method}") + raise SlackResponseError(f"Failed to fetch sample data from Slack API: ok=false for method={API_METHOD}") return response diff --git a/tests/listeners/functions/test_filters.py b/tests/listeners/functions/test_filters.py index 936775b..45159d0 100644 --- a/tests/listeners/functions/test_filters.py +++ b/tests/listeners/functions/test_filters.py @@ -25,13 +25,14 @@ def setup_method(self): ], }, { - "name": "type", - "display_name": "Type", - "type": "multi_select", - "options": [ - {"name": "Template", "value": "template"}, - {"name": "Sample", "value": "sample"}, - ], + "name": "template", + "display_name": "Templates", + "type": "toggle", + }, + { + "name": "sample", + "display_name": "Samples", + "type": "toggle", }, ] @@ -39,7 +40,11 @@ def test_filters_step_callback_success(self): inputs = {"user_context": {"id": "U123456"}} filters_step_callback( - ack=self.mock_ack, inputs=inputs, fail=self.mock_fail, complete=self.mock_complete, logger=self.mock_logger + ack=self.mock_ack, + inputs=inputs, + fail=self.mock_fail, + complete=self.mock_complete, + logger=self.mock_logger, ) self.mock_complete.assert_called_once() @@ -52,7 +57,11 @@ def test_filters_step_callback_success(self): def test_filters_step_callback_empty_user_context(self): filters_step_callback( - ack=self.mock_ack, inputs={}, fail=self.mock_fail, complete=self.mock_complete, logger=self.mock_logger + ack=self.mock_ack, + inputs={}, + fail=self.mock_fail, + complete=self.mock_complete, + logger=self.mock_logger, ) self.mock_complete.assert_called_once() @@ -66,7 +75,11 @@ def test_filters_step_callback_unexpected_exception(self): self.mock_complete.side_effect = Exception("Unexpected error") filters_step_callback( - ack=self.mock_ack, inputs={}, fail=self.mock_fail, complete=self.mock_complete, logger=self.mock_logger + ack=self.mock_ack, + inputs={}, + fail=self.mock_fail, + complete=self.mock_complete, + logger=self.mock_logger, ) self.mock_fail.assert_called_once() diff --git a/tests/listeners/functions/test_search.py b/tests/listeners/functions/test_search.py index b26ff1d..f83a40d 100644 --- a/tests/listeners/functions/test_search.py +++ b/tests/listeners/functions/test_search.py @@ -3,6 +3,7 @@ from slack_bolt import Ack, Complete, Fail from slack_sdk import WebClient +from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER, TEMPLATES_FILTER from listeners.functions.search import SEARCH_PROCESSING_ERROR_MSG, search_step_callback from listeners.sample_data_service import SlackResponseError @@ -39,8 +40,10 @@ def setup_method(self): @patch("listeners.functions.search.fetch_sample_data") def test_search_step_callback_success(self, mock_fetch_sample_data): mock_fetch_sample_data.return_value = self.mock_sample_data + + filters = {LANGUAGES_FILTER.name: ["python"]} - inputs = {"query": "test query", "filters": {"languages": ["python"], "type": ["code"]}} + inputs = {"query": "test query", "filters": filters} search_step_callback( ack=self.mock_ack, @@ -54,18 +57,51 @@ def test_search_step_callback_success(self, mock_fetch_sample_data): mock_fetch_sample_data.assert_called_once_with( client=self.mock_client, query="test query", - filters={"languages": ["python"], "type": "code"}, + filters=filters, logger=self.mock_logger, ) self.mock_complete.assert_called_once() call_args = self.mock_complete.call_args outputs = call_args.kwargs["outputs"] + assert outputs["search_result"] == self.mock_sample_data["samples"] self.mock_ack.assert_called_once() self.mock_fail.assert_not_called() + + @patch("listeners.functions.search.fetch_sample_data") + def test_search_step_callback_multiple_filter_types(self, mock_fetch_sample_data): + mock_fetch_sample_data.return_value = self.mock_sample_data + + filters = { + TEMPLATES_FILTER.name: True, + SAMPLES_FILTER.name: True, + LANGUAGES_FILTER.name: ["python", "javascript"] + } + + inputs = {"query": "test query", "filters": filters} + + search_step_callback( + ack=self.mock_ack, + inputs=inputs, + fail=self.mock_fail, + complete=self.mock_complete, + client=self.mock_client, + logger=self.mock_logger, + ) + + mock_fetch_sample_data.assert_called_once_with( + client=self.mock_client, + query="test query", + filters=filters, + logger=self.mock_logger, + ) + + self.mock_complete.assert_called_once() + self.mock_ack.assert_called_once() + @patch("listeners.functions.search.fetch_sample_data") def test_search_step_callback_no_filters(self, mock_fetch_sample_data): mock_fetch_sample_data.return_value = {"samples": []} @@ -80,7 +116,10 @@ def test_search_step_callback_no_filters(self, mock_fetch_sample_data): ) mock_fetch_sample_data.assert_called_once_with( - client=self.mock_client, query="test query", filters={}, logger=self.mock_logger + client=self.mock_client, + query="test query", + filters=None, + logger=self.mock_logger ) self.mock_complete.assert_called_once() @@ -123,27 +162,8 @@ def test_search_step_callback_unexpected_exception(self, mock_fetch_sample_data) logger=self.mock_logger, ) + self.mock_logger.error.assert_called_once() + self.mock_fail.assert_not_called() self.mock_complete.assert_not_called() self.mock_ack.assert_called_once() - - @patch("listeners.functions.search.fetch_sample_data") - def test_search_step_callback_multiple_type_filters(self, mock_fetch_sample_data): - mock_fetch_sample_data.return_value = {"samples": []} - - inputs = {"query": "test query", "filters": {"type": ["code", "document"]}} - - search_step_callback( - ack=self.mock_ack, - inputs=inputs, - fail=self.mock_fail, - complete=self.mock_complete, - client=self.mock_client, - logger=self.mock_logger, - ) - - mock_fetch_sample_data.assert_called_once_with( - client=self.mock_client, query="test query", filters={}, logger=self.mock_logger - ) - - self.mock_complete.assert_called_once() diff --git a/tests/listeners/test_sample_data_service.py b/tests/listeners/test_sample_data_service.py new file mode 100644 index 0000000..9365523 --- /dev/null +++ b/tests/listeners/test_sample_data_service.py @@ -0,0 +1,159 @@ +from unittest.mock import MagicMock +import pytest + +from slack_sdk import WebClient + +from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER, TEMPLATES_FILTER +from listeners.sample_data_service import API_METHOD, SlackResponseError, fetch_sample_data + + +class TestSampleDataService: + def setup_method(self): + self.mock_client = MagicMock(spec=WebClient) + self.mock_logger = MagicMock() + + self.mock_response = { + "ok": True, + "samples": [ + { + "title": "Sample 1", + "description": "Description 1", + "link": "https://example.com/1", + "date_updated": "2023-01-01", + "external_ref": {"id": "sample1"}, + }, + { + "title": "Sample 2", + "description": "Description 2", + "link": "https://example.com/2", + "date_updated": "2023-01-02", + "external_ref": {"id": "sample2"}, + "content": "Full content here", + }, + ], + } + + self.mock_client.api_call.return_value = self.mock_response + + def test_fetch_sample_data_no_filters(self): + result = fetch_sample_data(client=self.mock_client, logger=self.mock_logger) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": None} + ) + assert result == self.mock_response + + def test_fetch_sample_data_with_query(self): + result = fetch_sample_data( + client=self.mock_client, + query="test query", + logger=self.mock_logger + ) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": "test query"} + ) + assert result == self.mock_response + + def test_fetch_sample_data_with_languages_filter(self): + filters = {LANGUAGES_FILTER.name: ["python", "javascript"]} + + result = fetch_sample_data( + client=self.mock_client, + query="test query", + filters=filters, + logger=self.mock_logger + ) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": "test query", "filters": filters} + ) + + assert result == self.mock_response + + def test_fetch_sample_data_with_templates_filter(self): + filters = {TEMPLATES_FILTER.name: True} + + result = fetch_sample_data( + client=self.mock_client, + query="test query", + filters=filters, + logger=self.mock_logger + ) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": "test query", "filters": {"type": TEMPLATES_FILTER.name}} + ) + + assert result == self.mock_response + + def test_fetch_sample_data_with_samples_filter(self): + filters = {SAMPLES_FILTER.name: True} + + result = fetch_sample_data( + client=self.mock_client, + query="test query", + filters=filters, + logger=self.mock_logger + ) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": "test query", "filters": {"type": SAMPLES_FILTER.name}} + ) + + assert result == self.mock_response + + def test_fetch_sample_data_with_combined_filters(self): + filters = { + LANGUAGES_FILTER.name: ["python"], + TEMPLATES_FILTER.name: True + } + + result = fetch_sample_data( + client=self.mock_client, + query="test query", + filters=filters, + logger=self.mock_logger + ) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": "test query", "filters": {LANGUAGES_FILTER.name: ["python"], "type": TEMPLATES_FILTER.name}} + ) + + assert result == self.mock_response + + def test_fetch_sample_data_with_both_template_and_sample(self): + filters = { + TEMPLATES_FILTER.name: True, + SAMPLES_FILTER.name: True + } + + result = fetch_sample_data( + client=self.mock_client, + query="test query", + filters=filters, + logger=self.mock_logger + ) + + self.mock_client.api_call.assert_called_once_with( + API_METHOD, params={"query": "test query"} + ) + + assert result == self.mock_response + + def test_fetch_sample_data_api_error(self): + error_response = {"ok": False, "error": "invalid_auth"} + self.mock_client.api_call.return_value = error_response + + with pytest.raises(SlackResponseError) as excinfo: + fetch_sample_data( + client=self.mock_client, + query="test query", + logger=self.mock_logger + ) + + # Verify error was logged + self.mock_logger.error.assert_called_once() + + # Verify exception message + assert f"Failed to fetch sample data from Slack API: ok=false for method={API_METHOD}" in str(excinfo.value) From 6b6654158e943bba6775ab5f72b323dd285a4380 Mon Sep 17 00:00:00 2001 From: William Bergamin Date: Tue, 21 Oct 2025 17:03:43 -0400 Subject: [PATCH 2/3] Improve template based on feedback --- listeners/filters.py | 4 +- listeners/functions/filters.py | 5 +- listeners/functions/search.py | 3 - listeners/sample_data_service.py | 1 - tests/listeners/functions/test_filters.py | 3 +- tests/listeners/functions/test_search.py | 18 +-- tests/listeners/test_sample_data_service.py | 120 ++++++-------------- 7 files changed, 51 insertions(+), 103 deletions(-) diff --git a/listeners/filters.py b/listeners/filters.py index 55c705b..ae6c186 100644 --- a/listeners/filters.py +++ b/listeners/filters.py @@ -19,12 +19,14 @@ class Filter: name: str display_name: str type: FilterType + display_name_plural: Optional[str] = None options: Optional[List[FilterOptions]] = None LANGUAGES_FILTER = Filter( name="languages", - display_name="Languages", + display_name="Language", + display_name_plural="Languages", type=FilterType.MULTI_SELECT.value, options=[ FilterOptions(name="Python", value="python"), diff --git a/listeners/functions/filters.py b/listeners/functions/filters.py index 87fe26a..1904370 100644 --- a/listeners/functions/filters.py +++ b/listeners/functions/filters.py @@ -1,5 +1,6 @@ import logging from dataclasses import asdict +from typing import Dict from slack_bolt import Ack, Complete, Fail @@ -9,7 +10,9 @@ "We encountered an issue processing filter results. Please try again or contact the app owner if the problem persists." ) -filter_none = lambda items: {k: v for k, v in items if v is not None} +def filter_none(items: Dict): + return {k: v for k, v in items if v is not None} + def filters_step_callback(ack: Ack, inputs: dict, fail: Fail, complete: Complete, logger: logging.Logger): try: diff --git a/listeners/functions/search.py b/listeners/functions/search.py index eab2406..4d99db5 100644 --- a/listeners/functions/search.py +++ b/listeners/functions/search.py @@ -4,7 +4,6 @@ from slack_bolt import Ack, Complete, Fail from slack_sdk import WebClient -from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER from listeners.sample_data_service import SlackResponseError, fetch_sample_data SEARCH_PROCESSING_ERROR_MSG = ( @@ -12,8 +11,6 @@ "Please try again or contact the app owner if the problem persists." ) -print(SEARCH_PROCESSING_ERROR_MSG) - class EntityReference(TypedDict): id: str diff --git a/listeners/sample_data_service.py b/listeners/sample_data_service.py index 65eb1b2..b61bdb3 100644 --- a/listeners/sample_data_service.py +++ b/listeners/sample_data_service.py @@ -1,4 +1,3 @@ -import json import logging from slack_sdk import WebClient diff --git a/tests/listeners/functions/test_filters.py b/tests/listeners/functions/test_filters.py index 45159d0..ae8d364 100644 --- a/tests/listeners/functions/test_filters.py +++ b/tests/listeners/functions/test_filters.py @@ -15,8 +15,9 @@ def setup_method(self): self.expected_filters = [ { "name": "languages", - "display_name": "Languages", + "display_name": "Language", "type": "multi_select", + "display_name_plural": "Languages", "options": [ {"name": "Python", "value": "python"}, {"name": "Java", "value": "java"}, diff --git a/tests/listeners/functions/test_search.py b/tests/listeners/functions/test_search.py index f83a40d..9c26777 100644 --- a/tests/listeners/functions/test_search.py +++ b/tests/listeners/functions/test_search.py @@ -40,7 +40,7 @@ def setup_method(self): @patch("listeners.functions.search.fetch_sample_data") def test_search_step_callback_success(self, mock_fetch_sample_data): mock_fetch_sample_data.return_value = self.mock_sample_data - + filters = {LANGUAGES_FILTER.name: ["python"]} inputs = {"query": "test query", "filters": filters} @@ -64,22 +64,17 @@ def test_search_step_callback_success(self, mock_fetch_sample_data): self.mock_complete.assert_called_once() call_args = self.mock_complete.call_args outputs = call_args.kwargs["outputs"] - + assert outputs["search_result"] == self.mock_sample_data["samples"] self.mock_ack.assert_called_once() self.mock_fail.assert_not_called() - @patch("listeners.functions.search.fetch_sample_data") def test_search_step_callback_multiple_filter_types(self, mock_fetch_sample_data): mock_fetch_sample_data.return_value = self.mock_sample_data - filters = { - TEMPLATES_FILTER.name: True, - SAMPLES_FILTER.name: True, - LANGUAGES_FILTER.name: ["python", "javascript"] - } + filters = {TEMPLATES_FILTER.name: True, SAMPLES_FILTER.name: True, LANGUAGES_FILTER.name: ["python", "javascript"]} inputs = {"query": "test query", "filters": filters} @@ -116,10 +111,7 @@ def test_search_step_callback_no_filters(self, mock_fetch_sample_data): ) mock_fetch_sample_data.assert_called_once_with( - client=self.mock_client, - query="test query", - filters=None, - logger=self.mock_logger + client=self.mock_client, query="test query", filters=None, logger=self.mock_logger ) self.mock_complete.assert_called_once() @@ -163,7 +155,7 @@ def test_search_step_callback_unexpected_exception(self, mock_fetch_sample_data) ) self.mock_logger.error.assert_called_once() - + self.mock_fail.assert_not_called() self.mock_complete.assert_not_called() self.mock_ack.assert_called_once() diff --git a/tests/listeners/test_sample_data_service.py b/tests/listeners/test_sample_data_service.py index 9365523..06d543e 100644 --- a/tests/listeners/test_sample_data_service.py +++ b/tests/listeners/test_sample_data_service.py @@ -1,6 +1,6 @@ from unittest.mock import MagicMock -import pytest +import pytest from slack_sdk import WebClient from listeners.filters import LANGUAGES_FILTER, SAMPLES_FILTER, TEMPLATES_FILTER @@ -11,7 +11,7 @@ class TestSampleDataService: def setup_method(self): self.mock_client = MagicMock(spec=WebClient) self.mock_logger = MagicMock() - + self.mock_response = { "ok": True, "samples": [ @@ -32,128 +32,82 @@ def setup_method(self): }, ], } - + self.mock_client.api_call.return_value = self.mock_response def test_fetch_sample_data_no_filters(self): result = fetch_sample_data(client=self.mock_client, logger=self.mock_logger) - - self.mock_client.api_call.assert_called_once_with( - API_METHOD, params={"query": None} - ) + + self.mock_client.api_call.assert_called_once_with(API_METHOD, params={"query": None}) assert result == self.mock_response def test_fetch_sample_data_with_query(self): - result = fetch_sample_data( - client=self.mock_client, - query="test query", - logger=self.mock_logger - ) - - self.mock_client.api_call.assert_called_once_with( - API_METHOD, params={"query": "test query"} - ) + result = fetch_sample_data(client=self.mock_client, query="test query", logger=self.mock_logger) + + self.mock_client.api_call.assert_called_once_with(API_METHOD, params={"query": "test query"}) assert result == self.mock_response def test_fetch_sample_data_with_languages_filter(self): filters = {LANGUAGES_FILTER.name: ["python", "javascript"]} - - result = fetch_sample_data( - client=self.mock_client, - query="test query", - filters=filters, - logger=self.mock_logger - ) - self.mock_client.api_call.assert_called_once_with( - API_METHOD, params={"query": "test query", "filters": filters} - ) - + result = fetch_sample_data(client=self.mock_client, query="test query", filters=filters, logger=self.mock_logger) + + self.mock_client.api_call.assert_called_once_with(API_METHOD, params={"query": "test query", "filters": filters}) + assert result == self.mock_response def test_fetch_sample_data_with_templates_filter(self): filters = {TEMPLATES_FILTER.name: True} - - result = fetch_sample_data( - client=self.mock_client, - query="test query", - filters=filters, - logger=self.mock_logger - ) - + + result = fetch_sample_data(client=self.mock_client, query="test query", filters=filters, logger=self.mock_logger) + self.mock_client.api_call.assert_called_once_with( API_METHOD, params={"query": "test query", "filters": {"type": TEMPLATES_FILTER.name}} ) - + assert result == self.mock_response def test_fetch_sample_data_with_samples_filter(self): filters = {SAMPLES_FILTER.name: True} - - result = fetch_sample_data( - client=self.mock_client, - query="test query", - filters=filters, - logger=self.mock_logger - ) - + + result = fetch_sample_data(client=self.mock_client, query="test query", filters=filters, logger=self.mock_logger) + self.mock_client.api_call.assert_called_once_with( API_METHOD, params={"query": "test query", "filters": {"type": SAMPLES_FILTER.name}} ) - + assert result == self.mock_response def test_fetch_sample_data_with_combined_filters(self): - filters = { - LANGUAGES_FILTER.name: ["python"], - TEMPLATES_FILTER.name: True - } - - result = fetch_sample_data( - client=self.mock_client, - query="test query", - filters=filters, - logger=self.mock_logger - ) - + filters = {LANGUAGES_FILTER.name: ["python"], TEMPLATES_FILTER.name: True} + + result = fetch_sample_data(client=self.mock_client, query="test query", filters=filters, logger=self.mock_logger) + self.mock_client.api_call.assert_called_once_with( - API_METHOD, params={"query": "test query", "filters": {LANGUAGES_FILTER.name: ["python"], "type": TEMPLATES_FILTER.name}} + API_METHOD, + params={"query": "test query", "filters": {LANGUAGES_FILTER.name: ["python"], "type": TEMPLATES_FILTER.name}}, ) - + assert result == self.mock_response def test_fetch_sample_data_with_both_template_and_sample(self): - filters = { - TEMPLATES_FILTER.name: True, - SAMPLES_FILTER.name: True - } - - result = fetch_sample_data( - client=self.mock_client, - query="test query", - filters=filters, - logger=self.mock_logger - ) - - self.mock_client.api_call.assert_called_once_with( - API_METHOD, params={"query": "test query"} - ) - + filters = {TEMPLATES_FILTER.name: True, SAMPLES_FILTER.name: True} + + result = fetch_sample_data(client=self.mock_client, query="test query", filters=filters, logger=self.mock_logger) + + self.mock_client.api_call.assert_called_once_with(API_METHOD, params={"query": "test query"}) + assert result == self.mock_response def test_fetch_sample_data_api_error(self): error_response = {"ok": False, "error": "invalid_auth"} self.mock_client.api_call.return_value = error_response - + with pytest.raises(SlackResponseError) as excinfo: - fetch_sample_data( - client=self.mock_client, - query="test query", - logger=self.mock_logger - ) - + fetch_sample_data(client=self.mock_client, query="test query", logger=self.mock_logger) + # Verify error was logged self.mock_logger.error.assert_called_once() - + # Verify exception message assert f"Failed to fetch sample data from Slack API: ok=false for method={API_METHOD}" in str(excinfo.value) From d50a1e431d8f370f8f91164022180a8c09f7f88e Mon Sep 17 00:00:00 2001 From: William Bergamin Date: Tue, 21 Oct 2025 17:16:34 -0400 Subject: [PATCH 3/3] clean up --- tests/listeners/functions/test_filters.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/listeners/functions/test_filters.py b/tests/listeners/functions/test_filters.py index ae8d364..f55b6b5 100644 --- a/tests/listeners/functions/test_filters.py +++ b/tests/listeners/functions/test_filters.py @@ -85,7 +85,6 @@ def test_filters_step_callback_unexpected_exception(self): self.mock_fail.assert_called_once() call_args = self.mock_fail.call_args - print(FILTER_PROCESSING_ERROR_MSG) assert call_args.kwargs["error"] == FILTER_PROCESSING_ERROR_MSG self.mock_ack.assert_called_once()