diff --git a/CHANGELOG.md b/CHANGELOG.md index 6575df5..8fbc51b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.5.0] - 2026-04-08 + +### Added +- IT Dashboard investments: `list_itdashboard_investments`, `get_itdashboard_investment` (`/api/itdashboard/`) with shaping and filter params (`search`, `agency_code`, `agency_name`, `type_of_investment`, `updated_time_after`, `updated_time_before`, `cio_rating`, `cio_rating_max`, `performance_risk`). Tier-gated by the API: free tier gets `search`, pro adds structured filters, business+ adds CIO/performance analytics. New `ITDashboardInvestment` model and `ShapeConfig.ITDASHBOARD_INVESTMENTS_MINIMAL` / `ITDASHBOARD_INVESTMENTS_COMPREHENSIVE` defaults. + +## [0.4.4] - 2026-03-25 + +### Added +- `parent_piid` filter parameter on `list_contracts` for filtering orders under a specific parent IDV PIID. +- `user_agent` and `extra_headers` parameters on `TangoClient` for custom request headers. +- `TangoClient.last_response_headers` property for accessing full HTTP headers from the most recent API response. + ## [0.4.3] - 2026-03-21 ### Added diff --git a/pyproject.toml b/pyproject.toml index 7d36563..640b5c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "tango-python" -version = "0.4.3" +version = "0.5.0" description = "Python SDK for the Tango API" readme = "README.md" requires-python = ">=3.12" diff --git a/scripts/check_filter_shape_conformance.py b/scripts/check_filter_shape_conformance.py index 640e5fe..298f2cd 100644 --- a/scripts/check_filter_shape_conformance.py +++ b/scripts/check_filter_shape_conformance.py @@ -50,6 +50,7 @@ "agencies": "list_agencies", "naics": "list_naics", "gsa_elibrary_contracts": "list_gsa_elibrary_contracts", + "itdashboard": "list_itdashboard_investments", # Resources not yet implemented in SDK "offices": None, } @@ -66,6 +67,7 @@ def get_shape_config_entries() -> list[tuple[str, str, type[Any]]]: Forecast, Grant, GsaElibraryContract, + ITDashboardInvestment, Notice, Opportunity, Organization, @@ -98,6 +100,16 @@ def get_shape_config_entries() -> list[tuple[str, str, type[Any]]]: ShapeConfig.GSA_ELIBRARY_CONTRACTS_MINIMAL, GsaElibraryContract, ), + ( + "ITDASHBOARD_INVESTMENTS_MINIMAL", + ShapeConfig.ITDASHBOARD_INVESTMENTS_MINIMAL, + ITDashboardInvestment, + ), + ( + "ITDASHBOARD_INVESTMENTS_COMPREHENSIVE", + ShapeConfig.ITDASHBOARD_INVESTMENTS_COMPREHENSIVE, + ITDashboardInvestment, + ), ] for name, shape_str, model_cls in configs: entries.append((name, shape_str, model_cls)) diff --git a/tango/__init__.py b/tango/__init__.py index 480cf84..ff0d6f5 100644 --- a/tango/__init__.py +++ b/tango/__init__.py @@ -10,6 +10,7 @@ ) from .models import ( GsaElibraryContract, + ITDashboardInvestment, PaginatedResponse, RateLimitInfo, SearchFilters, @@ -28,7 +29,7 @@ TypeGenerator, ) -__version__ = "0.4.3" +__version__ = "0.5.0" __all__ = [ "TangoClient", "TangoAPIError", @@ -38,6 +39,7 @@ "TangoRateLimitError", "RateLimitInfo", "GsaElibraryContract", + "ITDashboardInvestment", "PaginatedResponse", "SearchFilters", "ShapeConfig", diff --git a/tango/client.py b/tango/client.py index 15e3f44..2d29c36 100644 --- a/tango/client.py +++ b/tango/client.py @@ -26,6 +26,7 @@ Forecast, Grant, GsaElibraryContract, + ITDashboardInvestment, Location, Notice, Opportunity, @@ -59,6 +60,8 @@ def __init__( self, api_key: str | None = None, base_url: str = "https://tango.makegov.com", + user_agent: str | None = None, + extra_headers: dict[str, str] | None = None, ): """ Initialize the Tango API client @@ -67,6 +70,8 @@ def __init__( api_key: API key for authentication. If not provided, will attempt to load from TANGO_API_KEY environment variable. base_url: Base URL for the API + user_agent: Custom User-Agent header value. + extra_headers: Additional headers to include in every request. """ # Load API key from environment if not provided self.api_key = api_key or os.getenv("TANGO_API_KEY") @@ -76,9 +81,14 @@ def __init__( headers = {} if self.api_key: headers["X-API-KEY"] = self.api_key + if user_agent: + headers["User-Agent"] = user_agent + if extra_headers: + headers.update(extra_headers) self.client = httpx.Client(headers=headers, timeout=30.0) self._last_rate_limit_info: RateLimitInfo | None = None + self._last_response_headers: httpx.Headers | None = None # Use hardcoded sensible defaults cache_size = 100 @@ -105,6 +115,11 @@ def rate_limit_info(self) -> RateLimitInfo | None: """Rate limit info from the most recent API response.""" return self._last_rate_limit_info + @property + def last_response_headers(self) -> httpx.Headers | None: + """Full HTTP headers from the most recent API response.""" + return self._last_response_headers + @staticmethod def _parse_rate_limit_headers(headers: httpx.Headers) -> RateLimitInfo: """Extract rate limit info from response headers.""" @@ -140,6 +155,7 @@ def _request( try: response = self.client.request(method=method, url=url, params=params, json=json_data) + self._last_response_headers = response.headers self._last_rate_limit_info = self._parse_rate_limit_headers(response.headers) if response.status_code == 401: @@ -1321,6 +1337,112 @@ def get_gsa_elibrary_contract( data, shape, GsaElibraryContract, flat, flat_lists, joiner=joiner ) + # ============================================================================ + # IT Dashboard Investments + # ============================================================================ + + def list_itdashboard_investments( + self, + page: int = 1, + limit: int = 25, + shape: str | None = None, + flat: bool = False, + flat_lists: bool = False, + joiner: str = ".", + search: str | None = None, + agency_code: int | None = None, + agency_name: str | None = None, + type_of_investment: str | None = None, + updated_time_after: str | date | datetime | None = None, + updated_time_before: str | date | datetime | None = None, + cio_rating: int | None = None, + cio_rating_max: int | None = None, + performance_risk: bool | None = None, + ) -> PaginatedResponse: + """List federal IT investments from the IT Dashboard (`/api/itdashboard/`). + + Filters are tier-gated by the API: + + - **Free**: ``search`` (full-text across UII, title, description, agency, bureau) + - **Pro**: ``agency_code``, ``type_of_investment``, + ``updated_time_after`` / ``updated_time_before`` + - **Business+**: ``agency_name`` (text), ``cio_rating``, + ``cio_rating_max``, ``performance_risk`` + + Hitting a gated filter on a lower tier returns a 403 with upgrade info. + + CIO ratings: 1=High Risk, 2=Moderately High, 3=Medium, 4=Moderately Low, 5=Low. + ``performance_risk=True`` returns investments with at least one NOT MET metric. + """ + params: dict[str, Any] = {"page": page, "limit": min(limit, 100)} + if shape is None: + shape = ShapeConfig.ITDASHBOARD_INVESTMENTS_MINIMAL + if shape: + params["shape"] = shape + if flat: + params["flat"] = "true" + if joiner: + params["joiner"] = joiner + if flat_lists: + params["flat_lists"] = "true" + for k, val in ( + ("search", search), + ("agency_code", agency_code), + ("agency_name", agency_name), + ("type_of_investment", type_of_investment), + ("updated_time_after", updated_time_after), + ("updated_time_before", updated_time_before), + ("cio_rating", cio_rating), + ("cio_rating_max", cio_rating_max), + ("performance_risk", performance_risk), + ): + if val is None: + continue + if isinstance(val, bool): + params[k] = "true" if val else "false" + elif isinstance(val, (date, datetime)): + params[k] = val.isoformat() + else: + params[k] = val + data = self._get("/api/itdashboard/", params) + results = [ + self._parse_response_with_shape( + obj, shape, ITDashboardInvestment, flat, flat_lists, joiner=joiner + ) + for obj in data.get("results", []) + ] + return PaginatedResponse( + count=data.get("count", 0), + next=data.get("next"), + previous=data.get("previous"), + results=results, + ) + + def get_itdashboard_investment( + self, + uii: str, + shape: str | None = None, + flat: bool = False, + flat_lists: bool = False, + joiner: str = ".", + ) -> Any: + """Get a single IT Dashboard investment by UII (`/api/itdashboard/{uii}/`).""" + params: dict[str, Any] = {} + if shape is None: + shape = ShapeConfig.ITDASHBOARD_INVESTMENTS_COMPREHENSIVE + if shape: + params["shape"] = shape + if flat: + params["flat"] = "true" + if joiner: + params["joiner"] = joiner + if flat_lists: + params["flat_lists"] = "true" + data = self._get(f"/api/itdashboard/{uii}/", params) + return self._parse_response_with_shape( + data, shape, ITDashboardInvestment, flat, flat_lists, joiner=joiner + ) + # ============================================================================ # Vehicles (Awards) # ============================================================================ diff --git a/tango/models.py b/tango/models.py index 7347a0d..3cab2c0 100644 --- a/tango/models.py +++ b/tango/models.py @@ -367,6 +367,45 @@ class GsaElibraryContract: sins: list[str] | None = None +@dataclass +class ITDashboardInvestment: + """Schema definition for IT Dashboard Investment (not used for instances) + + Federal IT investment from itdashboard.gov, exposed at /api/itdashboard/. + Identified by ``uii`` (Unique Investment Identifier). + + Tier-gated shape expansions: + Free base fields only + Pro+ ``funding`` and ``details`` expansions + Business+ nested sub-tables (``cio_evaluation``, ``contracts``, + ``projects``, ``cost_pools_towers``, ``funding_sources``, + ``performance_metrics``, ``performance_actual``, + ``operational_analysis``) and ``business_case_html`` + """ + + uii: str + agency_code: int | None = None + agency_name: str | None = None + bureau_code: int | None = None + bureau_name: str | None = None + investment_title: str | None = None + type_of_investment: str | None = None + part_of_it_portfolio: str | None = None + updated_time: datetime | None = None + url: str | None = None + business_case_html: str | None = None + funding: dict[str, Any] | None = None + details: dict[str, Any] | None = None + cio_evaluation: list[dict[str, Any]] | None = None + contracts: list[dict[str, Any]] | None = None + projects: list[dict[str, Any]] | None = None + cost_pools_towers: list[dict[str, Any]] | None = None + funding_sources: list[dict[str, Any]] | None = None + performance_metrics: list[dict[str, Any]] | None = None + performance_actual: list[dict[str, Any]] | None = None + operational_analysis: list[dict[str, Any]] | None = None + + @dataclass class Vehicle: """Schema definition for Vehicle (not used for instances)""" @@ -687,3 +726,18 @@ class ShapeConfig: GSA_ELIBRARY_CONTRACTS_MINIMAL: Final = ( "uuid,contract_number,schedule,recipient(display_name,uei),idv(key,award_date)" ) + + # Default for list_itdashboard_investments() + # Free-tier safe: matches the API's INVESTMENT_LIST_DEFAULT_SHAPE. + ITDASHBOARD_INVESTMENTS_MINIMAL: Final = ( + "uii,agency_name,bureau_name,investment_title," + "type_of_investment,part_of_it_portfolio,updated_time,url" + ) + + # Default for get_itdashboard_investment() + # Free-tier safe: matches the API's INVESTMENT_RETRIEVE_DEFAULT_SHAPE. + ITDASHBOARD_INVESTMENTS_COMPREHENSIVE: Final = ( + "uii,agency_code,agency_name,bureau_code,bureau_name," + "investment_title,type_of_investment,part_of_it_portfolio," + "updated_time,url" + ) diff --git a/tango/shapes/explicit_schemas.py b/tango/shapes/explicit_schemas.py index 3325883..3833cb6 100644 --- a/tango/shapes/explicit_schemas.py +++ b/tango/shapes/explicit_schemas.py @@ -1132,6 +1132,67 @@ ), } +# IT Dashboard Investment +ITDASHBOARD_INVESTMENT_SCHEMA: dict[str, FieldSchema] = { + "uii": FieldSchema(name="uii", type=str, is_optional=False, is_list=False), + "agency_code": FieldSchema( + name="agency_code", type=int, is_optional=True, is_list=False + ), + "agency_name": FieldSchema( + name="agency_name", type=str, is_optional=True, is_list=False + ), + "bureau_code": FieldSchema( + name="bureau_code", type=int, is_optional=True, is_list=False + ), + "bureau_name": FieldSchema( + name="bureau_name", type=str, is_optional=True, is_list=False + ), + "investment_title": FieldSchema( + name="investment_title", type=str, is_optional=True, is_list=False + ), + "type_of_investment": FieldSchema( + name="type_of_investment", type=str, is_optional=True, is_list=False + ), + "part_of_it_portfolio": FieldSchema( + name="part_of_it_portfolio", type=str, is_optional=True, is_list=False + ), + "updated_time": FieldSchema( + name="updated_time", type=datetime, is_optional=True, is_list=False + ), + "url": FieldSchema(name="url", type=str, is_optional=True, is_list=False), + "business_case_html": FieldSchema( + name="business_case_html", type=str, is_optional=True, is_list=False + ), + # Expansions: dict (funding/details) and list-of-dict (nested sub-tables). + # Modeled as opaque dict/list since their inner shapes are dynamic. + "funding": FieldSchema(name="funding", type=dict, is_optional=True, is_list=False), + "details": FieldSchema(name="details", type=dict, is_optional=True, is_list=False), + "cio_evaluation": FieldSchema( + name="cio_evaluation", type=list, is_optional=True, is_list=True + ), + "contracts": FieldSchema( + name="contracts", type=list, is_optional=True, is_list=True + ), + "projects": FieldSchema( + name="projects", type=list, is_optional=True, is_list=True + ), + "cost_pools_towers": FieldSchema( + name="cost_pools_towers", type=list, is_optional=True, is_list=True + ), + "funding_sources": FieldSchema( + name="funding_sources", type=list, is_optional=True, is_list=True + ), + "performance_metrics": FieldSchema( + name="performance_metrics", type=list, is_optional=True, is_list=True + ), + "performance_actual": FieldSchema( + name="performance_actual", type=list, is_optional=True, is_list=True + ), + "operational_analysis": FieldSchema( + name="operational_analysis", type=list, is_optional=True, is_list=True + ), +} + # ============================================================================ # SCHEMA REGISTRY MAPPING # ============================================================================ @@ -1176,6 +1237,8 @@ # GSA eLibrary "GsaElibraryContract": GSA_ELIBRARY_CONTRACT_SCHEMA, "GsaElibraryIdvRef": GSA_ELIBRARY_IDV_REF_SCHEMA, + # IT Dashboard + "ITDashboardInvestment": ITDASHBOARD_INVESTMENT_SCHEMA, } diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code b/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code new file mode 100644 index 0000000..83bb540 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code @@ -0,0 +1,95 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&agency_code=21 + response: + body: + string: '{"count":360,"next":"https://tango.makegov.com/api/itdashboard/?agency_code=21&limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"021-777552743","agency_name":"Department + of Transportation","bureau_name":"National Highway Traffic Safety Administration","investment_title":"NHTSA0020: + Artemis","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-03-27T12:45:58+00:00","url":"https://www.itdashboard.gov/investment-details/021-777552743"},{"uii":"021-302996650","agency_name":"Department + of Transportation","bureau_name":"National Highway Traffic Safety Administration","investment_title":"NHTSA0347: + CDAN Version 2.0","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-03-26T16:50:10+00:00","url":"https://www.itdashboard.gov/investment-details/021-302996650"},{"uii":"021-165719668","agency_name":"Department + of Transportation","bureau_name":"National Highway Traffic Safety Administration","investment_title":"NHTSA0301: + Teleprocessing and Timesharing Services for the NDR Program","type_of_investment":"Major + IT Investments","part_of_it_portfolio":"Part 1. IT Investments for Mission + Delivery","updated_time":"2026-03-26T16:49:35+00:00","url":"https://www.itdashboard.gov/investment-details/021-165719668"},{"uii":"021-700323071","agency_name":"Department + of Transportation","bureau_name":"Maritime Administration","investment_title":"MARAD0071: + National Security Multi-Mission Vessel (NSMV)","type_of_investment":"Major + IT Investments","part_of_it_portfolio":"Part 1. IT Investments for Mission + Delivery","updated_time":"2026-03-25T20:04:19+00:00","url":"https://www.itdashboard.gov/investment-details/021-700323071"},{"uii":"021-700323070","agency_name":"Department + of Transportation","bureau_name":"Maritime Administration","investment_title":"MARAD0070: + USMMA Campus Solutions (UCAS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-03-25T20:01:19+00:00","url":"https://www.itdashboard.gov/investment-details/021-700323070"}]}' + headers: + CF-RAY: + - 9e91f5012a290a26-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:11 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=3I21M9xblZ6mvJlcfLRR%2BgHPPkc4av1Jh5BnY2zzrEEQYRrjfLQYZ4wTjxthr51w2nNIPM4ww3TdtKdPPM%2BaPRa4lwu7%2F7SO1IC%2FtbBfAEYkTD6KuUhLQTtsgw8tF%2BSst8l8wPVEBcI8NpySZKvr"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2305' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.024s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '991' + x-ratelimit-burst-reset: + - '54' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999933' + x-ratelimit-daily-reset: + - '34308' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '991' + x-ratelimit-reset: + - '54' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text b/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text new file mode 100644 index 0000000..0b505a3 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text @@ -0,0 +1,93 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&agency_name=defense + response: + body: + string: '{"count":2655,"next":"https://tango.makegov.com/api/itdashboard/?agency_name=defense&limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"007-000103860","agency_name":"Department + of Defense","bureau_name":"Army","investment_title":"ENTERPRISE BUSINESS SYSTEMS-CONVERGENCE","type_of_investment":"Major + IT Investments","part_of_it_portfolio":"Part 2. IT Investments for Mission + Support Services","updated_time":"2026-02-24T15:47:57+00:00","url":"https://www.itdashboard.gov/investment-details/007-000103860"},{"uii":"007-000103486","agency_name":"Department + of Defense","bureau_name":"Navy, Marine Corps","investment_title":"Naval - + Maintenance, Repair, and Overhaul","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-02-24T15:47:56+00:00","url":"https://www.itdashboard.gov/investment-details/007-000103486"},{"uii":"007-000103389","agency_name":"Department + of Defense","bureau_name":"Navy, Marine Corps","investment_title":"Navy Personnel + and Pay","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-02-24T15:47:55+00:00","url":"https://www.itdashboard.gov/investment-details/007-000103389"},{"uii":"007-000101162","agency_name":"Department + of Defense","bureau_name":"Defense-wide","investment_title":"DEFENSE AGENCIES + INITIATIVE","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-02-24T15:47:53+00:00","url":"https://www.itdashboard.gov/investment-details/007-000101162"},{"uii":"007-000101099","agency_name":"Department + of Defense","bureau_name":"Defense-wide","investment_title":"Advancing Analytics","type_of_investment":"Major + IT Investments","part_of_it_portfolio":"Part 2. IT Investments for Mission + Support Services","updated_time":"2026-02-24T15:47:52+00:00","url":"https://www.itdashboard.gov/investment-details/007-000101099"}]}' + headers: + CF-RAY: + - 9e91f50efa00eb60-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:13 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=sVGRzZBXm8exykIK%2FejvOiYFHW4PdBAjQzVz8kFHaHvTKCThUTCPOdvSEmryfb1TOd2h6HWHaT4KLsBDgJFFcRVZqkYNjm32asNjoEnEg0wBrzakieSIJwfowtZYZjmpTn8HD%2BUTJzKIKlf6QARk"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2133' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.023s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '988' + x-ratelimit-burst-reset: + - '52' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999930' + x-ratelimit-daily-reset: + - '34306' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '988' + x-ratelimit-reset: + - '52' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating b/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating new file mode 100644 index 0000000..571913d --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating @@ -0,0 +1,94 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&cio_rating=1 + response: + body: + string: '{"count":8,"next":"https://tango.makegov.com/api/itdashboard/?cio_rating=1&limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000533","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"COM Solutions + Modernization","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:04:06+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000533"},{"uii":"010-000002832","agency_name":"Department + of the Interior","bureau_name":"Departmental Offices","investment_title":"DOI + - IBC Time & Attendance","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-03-16T20:38:44+00:00","url":"https://www.itdashboard.gov/investment-details/010-000002832"},{"uii":"007-000103389","agency_name":"Department + of Defense","bureau_name":"Navy, Marine Corps","investment_title":"Navy Personnel + and Pay","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-02-24T15:47:55+00:00","url":"https://www.itdashboard.gov/investment-details/007-000103389"},{"uii":"021-130077684","agency_name":"Department + of Transportation","bureau_name":"Federal Aviation Administration","investment_title":"FAAXX711: + Data Communications NextGen Support (DataComm)","type_of_investment":"Major + IT Investments","part_of_it_portfolio":"Part 1. IT Investments for Mission + Delivery","updated_time":"2025-09-29T22:01:34+00:00","url":"https://www.itdashboard.gov/investment-details/021-130077684"}]}' + headers: + CF-RAY: + - 9e91f5139db7edc5-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:14 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=3EXlOC16cG9P2yLN7rz2YxwmMHyB%2BASRQmSjD9NXeULjtV6qNnAtcbGbdzJ7hPhSr0xZQq%2Bj%2BydDFN0%2Bmn3ZCkvoLrZnfyyPvQm9gn7orEs0JLPwvC4s7vAIzTgJ1kXRvnJt"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2137' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.050s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '987' + x-ratelimit-burst-reset: + - '51' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999929' + x-ratelimit-daily-reset: + - '34305' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '987' + x-ratelimit-reset: + - '51' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max b/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max new file mode 100644 index 0000000..28a12e5 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max @@ -0,0 +1,93 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&cio_rating_max=2 + response: + body: + string: '{"count":47,"next":"https://tango.makegov.com/api/itdashboard/?cio_rating_max=2&limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"},{"uii":"014-000000469","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Enterprise + Architecture Information Management","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:23:01+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000469"},{"uii":"014-000000475","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Consular + Enterprise Infrastructure & Operations (EIO)","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:09:11+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000475"},{"uii":"014-000000533","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"COM Solutions + Modernization","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:04:06+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000533"}]}' + headers: + CF-RAY: + - 9e91f517dd281049-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:14 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=%2FxeiYPKaOs50ogY%2BAN0oMjsMPXQvLZsBlNVFIyTWtH4XPqq%2BMOrOeUqTfAlxV0nQkqPf%2Fb21tAMHxOuAtLzV3KnUlp0XD6tXV7nVA40PPmMXq7AUAheuC0oEI1r%2BoGTaetzZ"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2097' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.043s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '986' + x-ratelimit-burst-reset: + - '50' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999928' + x-ratelimit-daily-reset: + - '34305' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '986' + x-ratelimit-reset: + - '50' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk b/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk new file mode 100644 index 0000000..2a30613 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk @@ -0,0 +1,94 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&performance_risk=true + response: + body: + string: '{"count":222,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&performance_risk=true&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000012","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Integrated + Logistics Management System (ILMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-04-06T17:14:32+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000012"},{"uii":"014-000000524","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Integrated + Health Electronic Records Systems (iHERS)","type_of_investment":"Major IT + Investments","part_of_it_portfolio":"Part 2. IT Investments for Mission Support + Services","updated_time":"2026-04-06T16:54:39+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000524"},{"uii":"014-000000029","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Global Foreign + Affairs Compensation System (GFACS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-04-06T16:52:25+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000029"},{"uii":"014-000000483","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Contact + Relationship Management (CRM)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T15:41:28+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000483"}]}' + headers: + CF-RAY: + - 9e91f51ce9fd2986-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:15 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=PcxGdPY40jxAQBvtTRrH2D7KpJzN987PcvMzJziLt21eT9lmHzyrUsS95JcOexFoB4a7frgbo3VdAH3XAXOZp2oaQ5%2Bcnsw3nrCQFkSaow%2F0a9Y8QsV%2BP%2BPfWbLEiTYep2lt"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2215' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.034s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '985' + x-ratelimit-burst-reset: + - '50' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999927' + x-ratelimit-daily-reset: + - '34304' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '985' + x-ratelimit-reset: + - '50' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment b/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment new file mode 100644 index 0000000..48898f9 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment @@ -0,0 +1,94 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&type_of_investment=Major+IT+Investments + response: + body: + string: '{"count":574,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&type_of_investment=Major+IT+Investments","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000021","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"IRMS Operations + and Maintenance","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T17:32:59+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000021"},{"uii":"014-000000377","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Integrated + Security and Suitability System (Ice Cubed)","type_of_investment":"Major IT + Investments","part_of_it_portfolio":"Part 2. IT Investments for Mission Support + Services","updated_time":"2026-04-06T17:31:56+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000377"},{"uii":"014-000000024","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Integrated + Personnel Management System (IPMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-04-06T17:26:57+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000024"},{"uii":"014-000000012","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Integrated + Logistics Management System (ILMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 2. IT Investments for Mission Support Services","updated_time":"2026-04-06T17:14:32+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000012"}]}' + headers: + CF-RAY: + - 9e91f5067ffbff59-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:11 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Z851vzeF0bFORakClQMzDagyG6FihdmnGIoonpyLPSBj09mVHbV17Fsbto%2Ft0S1Lo8ma5wt0aOC9wC77Qaspm%2FboIQ%2BrbEstPQGN5Nw7w71D5jBvKfZ0QyQyM9DUJo3zODaHAYode6f2mo3lwkmD"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2224' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.022s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '990' + x-ratelimit-burst-reset: + - '53' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999932' + x-ratelimit-daily-reset: + - '34308' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '990' + x-ratelimit-reset: + - '53' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range b/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range new file mode 100644 index 0000000..c051c25 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range @@ -0,0 +1,93 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&updated_time_after=2026-01-01&updated_time_before=2026-12-31 + response: + body: + string: '{"count":355,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&updated_time_after=2026-01-01&updated_time_before=2026-12-31","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91f50b4e2ee264-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:12 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=RoXyVG3phspQ%2BhsPxatOvLS71fGeQRlca9LkbmrjZHnymrlrhcROj4jNXKK7yAZnKej9syU%2FoiDz5X8y5hymNTRC9UqMjpV7i6Cp%2F4dq2ieJiplD2pK0RdPEfSrPPDPJhzC1SAe38MZUa1UlNuSE"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2128' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.017s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '989' + x-ratelimit-burst-reset: + - '52' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999931' + x-ratelimit-daily-reset: + - '34307' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '989' + x-ratelimit-reset: + - '52' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions b/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions new file mode 100644 index 0000000..b6b697b --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions @@ -0,0 +1,88 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=3&shape=uii%2Cagency_name%2Cfunding%28%2A%29%2Ccio_evaluation%28%2A%29 + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=3&page=2&shape=uii%2Cagency_name%2Cfunding%28%2A%29%2Ccio_evaluation%28%2A%29","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","funding":{"fy2020_contribution":0.0,"fy2021_contribution":0.0,"fy2022_contribution":0.0,"fy2023_contribution":0.0,"fy2024_contribution":7.013587,"fy2025_contribution":2.913587,"fy2020_internal_funding":0.0,"fy2021_internal_funding":39.214195,"fy2022_internal_funding":40.517195,"fy2023_internal_funding":40.723195,"fy2024_internal_funding":26.626865,"fy2025_internal_funding":31.200073},"cio_evaluation":[{"comment":"Updated + the CIO Risk Rating to 3- Medium Risk based on internal agency evaluation.","cioRating":"3 + - Medium Risk","ratedDate":"2025-02-14","updatedTime":"2025-04-30 19:47:20","latestIndicator":"Y"}]},{"uii":"014-000000538","agency_name":"Department + of State","funding":{"fy2020_contribution":0.0,"fy2021_contribution":0.0,"fy2022_contribution":0.0,"fy2023_contribution":0.0,"fy2024_contribution":0.0,"fy2025_contribution":0.0,"fy2020_internal_funding":0.0,"fy2021_internal_funding":0.0,"fy2022_internal_funding":27.943398,"fy2023_internal_funding":20.375717,"fy2024_internal_funding":49.860823,"fy2025_internal_funding":43.509191},"cio_evaluation":[{"comment":"Our + CIO reviewed the current rating with no changes.","cioRating":"3 - Medium + Risk","ratedDate":"2025-02-14","updatedTime":"2025-03-31 19:51:18","latestIndicator":"Y"}]},{"uii":"014-000000498","agency_name":"Department + of State","funding":{"fy2020_contribution":0.0,"fy2021_contribution":0.0,"fy2022_contribution":6.169214,"fy2023_contribution":0.0,"fy2024_contribution":0.0,"fy2025_contribution":0.0,"fy2020_internal_funding":0.0,"fy2021_internal_funding":130.740066,"fy2022_internal_funding":175.482373,"fy2023_internal_funding":185.6068,"fy2024_internal_funding":185.556061,"fy2025_internal_funding":200.91797},"cio_evaluation":[{"comment":"Updated + the CIO Risk Rating to 4 - Moderately High Risk based on internal agency evaluation.","cioRating":"4 + - Moderately Low Risk","ratedDate":"2025-02-14","updatedTime":"2025-03-31 + 19:48:16","latestIndicator":"Y"}]}]}' + headers: + CF-RAY: + - 9e91f5225a5b140a-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:16 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=c2Hjys4568Iyl5PfHEVFcJr70SSu11UDlnDRutwzxGt1vOVEzEX%2BRt9TYxSf3WYHxL%2FTotxnh9TSsUkZb2aVqbuitLi%2FHV6EAE1qUS6X%2F569Ql0ND01BSAqUbkFXQmh9R9W9"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2178' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.028s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '984' + x-ratelimit-burst-reset: + - '49' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999926' + x-ratelimit-daily-reset: + - '34303' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '984' + x-ratelimit-reset: + - '49' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii b/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii new file mode 100644 index 0000000..7ab19fd --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii @@ -0,0 +1,314 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=1&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=1&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"}]}' + headers: + CF-RAY: + - 9e91ef98cec286d8-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:29 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=suXvkskd%2B%2B2rF71WlDXTA1ElFfnu%2BOJDc7bC01Uo8O5D%2BjN6X0MT2M39nHwsg72EKvtKitDriLAa50pDmaRFiLJzvluTfxpugUH%2F1IegV1hkVcMQXxT1Wqc2ROmj1vRXWmeA"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '614' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.022s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '993' + x-ratelimit-burst-reset: + - '56' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999983' + x-ratelimit-daily-reset: + - '34530' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '993' + x-ratelimit-reset: + - '56' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/014-000000018/?shape=uii%2Cagency_code%2Cagency_name%2Cbureau_code%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"uii":"014-000000018","agency_code":14,"agency_name":"Department of + State","bureau_code":0,"bureau_name":"Department of State","investment_title":"Joint + Financial Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"}' + headers: + CF-RAY: + - 9e91ef9ab80286d8-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:30 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=aFMGV8Hdzwv9MasMVneC1BySSDJOYBcgIAFNVylSsvq3NfxP2zq76Fwod%2Fi%2Bb6fkzAyQnEYzjyY9uGbpc5IAreSl7Mxb8uYdW8JW2KWe6Mqfdvy1gkl0fewY8Ar2dSDag%2Bfi"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '415' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.015s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '992' + x-ratelimit-burst-reset: + - '55' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999982' + x-ratelimit-daily-reset: + - '34530' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '992' + x-ratelimit-reset: + - '55' + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=1&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=1&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"}]}' + headers: + CF-RAY: + - 9e91f4f9fea8e8ea-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:10 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=5aOMGQdmVI8Up3OMx%2FBx2RVJ788ePg3OPobgIPjQGCmDl4MQBbZnVi1qCPrRdVZ56eXNAdy3UejXzU1HE5nC6ufEudVGw3qsxAx0%2FwMnzinUmrpEiC54p%2Fends2JgG9Y41vdPMl%2FSbXRlvLlELoL"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '614' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.022s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '993' + x-ratelimit-burst-reset: + - '55' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999935' + x-ratelimit-daily-reset: + - '34309' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '993' + x-ratelimit-reset: + - '55' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/014-000000018/?shape=uii%2Cagency_code%2Cagency_name%2Cbureau_code%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"uii":"014-000000018","agency_code":14,"agency_name":"Department of + State","bureau_code":0,"bureau_name":"Department of State","investment_title":"Joint + Financial Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"}' + headers: + CF-RAY: + - 9e91f4fc3cd2e8ea-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:10 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=4eBA4RXG2uyY8hB2lxy4OIJ4MHPsyfiYK7npiwg16wmPV7Wd4UAtoNpGhl05fCd0%2BWwQhBumAhgDSDk8R5fCKKC150jwGyccckD9hgcEzC1XzFcowcZMJTNmiudBGLJalwz5YOUr1IqDnlMyYr0t"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '415' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.019s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '992' + x-ratelimit-burst-reset: + - '55' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999934' + x-ratelimit-daily-reset: + - '34309' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '992' + x-ratelimit-reset: + - '55' + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination b/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination new file mode 100644 index 0000000..b29b593 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination @@ -0,0 +1,364 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91ef928cf161a9-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:28 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=fym%2FLVaEBpyx23ixpql3VlJ5MayZmQ5jshwZ3hpMyINH4fAZX0L8%2BZObYHVZ%2FWaicVvfH3QTeOrMuJdgsNA%2FajfWKkTAN69Vkm6ZyEE1tY%2FzXUB0ZFFGdzSJ4Enr2A301oC8"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2068' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.022s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '995' + x-ratelimit-burst-reset: + - '57' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999985' + x-ratelimit-daily-reset: + - '34531' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '995' + x-ratelimit-reset: + - '57' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=2&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=3&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":"https://tango.makegov.com/api/itdashboard/?limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","results":[{"uii":"014-000000049","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Enterprise + Planning, and Management Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:25:04+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000049"},{"uii":"014-000000469","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Enterprise + Architecture Information Management","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:23:01+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000469"},{"uii":"014-000000408","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"DS Information + and Security Management","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:19:35+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000408"},{"uii":"014-000000539","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Cyber Operations","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:12:55+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000539"},{"uii":"014-000000475","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Consular + Enterprise Infrastructure & Operations (EIO)","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:09:11+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000475"}]}' + headers: + CF-RAY: + - 9e91ef945ea761a9-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:29 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=zUHEPK%2FlD98GZyalr4792iB3CYpiGzRcbY8evbH7X8cI%2FOen4%2FnPWQL8N%2FkNCtB4VB8JP%2B7dGI%2BKL6lgRjnD6l3srthz1EvoUymfjRjMp0cVFwHe1on7IZpFfPvgkYFdiCX4"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2283' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.028s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '994' + x-ratelimit-burst-reset: + - '56' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999984' + x-ratelimit-daily-reset: + - '34531' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '994' + x-ratelimit-reset: + - '56' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91f4f31c2ff5fc-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:08 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=P932%2BqXIfh7YeySUnYvhaxTAkCp0%2BAdI%2FiVe582mK2aOhQkVo73Eyn72sPjaw9GSECQ4nLrGR4HKqeVsocUKLFOkkjEdA54NGIRdN7mpnDQPb5pdDTejThFTzRH9%2B5igPuOD"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2068' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.022s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '995' + x-ratelimit-burst-reset: + - '56' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999937' + x-ratelimit-daily-reset: + - '34311' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '995' + x-ratelimit-reset: + - '56' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=2&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=3&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":"https://tango.makegov.com/api/itdashboard/?limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","results":[{"uii":"014-000000049","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Enterprise + Planning, and Management Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:25:04+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000049"},{"uii":"014-000000469","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Enterprise + Architecture Information Management","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:23:01+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000469"},{"uii":"014-000000408","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"DS Information + and Security Management","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:19:35+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000408"},{"uii":"014-000000539","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Cyber Operations","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:12:55+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000539"},{"uii":"014-000000475","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Consular + Enterprise Infrastructure & Operations (EIO)","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:09:11+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000475"}]}' + headers: + CF-RAY: + - 9e91f4f549a1f5fc-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:09 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=hEorvXT4JMcVFeWbhFhsqAWt3cLeW9HDAyyxp%2BZLv7kf%2FF2O%2BgAs9EfFtcflzL2P37HyVdLN43Y73RpZkcH4nh3gYKj8CpH%2Fbv%2FOcnKeoT2Nkl83v6MlZ1q18Pp1geaSLIkG"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2283' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.021s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '994' + x-ratelimit-burst-reset: + - '56' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999936' + x-ratelimit-daily-reset: + - '34310' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '994' + x-ratelimit-reset: + - '56' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search new file mode 100644 index 0000000..863ab81 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search @@ -0,0 +1,182 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&search=cyber + response: + body: + string: '{"count":115,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&search=cyber&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000539","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Cyber Operations","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:12:55+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000539"},{"uii":"014-000000501","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"AIS Security + Infrastructure Support Program","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T18:52:35+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000501"},{"uii":"029-666666400","agency_name":"Department + of Veterans Affairs","bureau_name":"Department of Veterans Affairs","investment_title":"Benefits + Appeals","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-03-18T20:24:46+00:00","url":"https://www.itdashboard.gov/investment-details/029-666666400"},{"uii":"011-000003581","agency_name":"Department + of Justice","bureau_name":"Drug Enforcement Administration","investment_title":"DEA + IT Security","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-02-13T18:02:29+00:00","url":"https://www.itdashboard.gov/investment-details/011-000003581"},{"uii":"007-000100706","agency_name":"Department + of Defense","bureau_name":"Navy, Marine Corps","investment_title":"Navy Continuous + Training Environment (NCTE)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2025-12-24T02:19:13+00:00","url":"https://www.itdashboard.gov/investment-details/007-000100706"}]}' + headers: + CF-RAY: + - 9e91ef8d888d10ae-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:28 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=zohi3Odc0Qp7NW950p2nzTDtTT61v9z7S0Ygo8iYOZ4T%2Fg81RcMZRbz6%2BeUTXkhgsGmXKv4ySPQNpbLONwizqHgDicUj3aVNUO1XciHXNYzBrhJvWK61uYLcnf2o8utQhlQB"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2110' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.080s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '996' + x-ratelimit-burst-reset: + - '57' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999986' + x-ratelimit-daily-reset: + - '34532' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '996' + x-ratelimit-reset: + - '57' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl&search=cyber + response: + body: + string: '{"count":115,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&search=cyber&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000539","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Cyber Operations","type_of_investment":"Standard + IT Investments","part_of_it_portfolio":"Part 3. IT Standard IT Investments","updated_time":"2026-04-06T19:12:55+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000539"},{"uii":"014-000000501","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"AIS Security + Infrastructure Support Program","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T18:52:35+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000501"},{"uii":"029-666666400","agency_name":"Department + of Veterans Affairs","bureau_name":"Department of Veterans Affairs","investment_title":"Benefits + Appeals","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-03-18T20:24:46+00:00","url":"https://www.itdashboard.gov/investment-details/029-666666400"},{"uii":"011-000003581","agency_name":"Department + of Justice","bureau_name":"Drug Enforcement Administration","investment_title":"DEA + IT Security","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-02-13T18:02:29+00:00","url":"https://www.itdashboard.gov/investment-details/011-000003581"},{"uii":"007-000100706","agency_name":"Department + of Defense","bureau_name":"Navy, Marine Corps","investment_title":"Navy Continuous + Training Environment (NCTE)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2025-12-24T02:19:13+00:00","url":"https://www.itdashboard.gov/investment-details/007-000100706"}]}' + headers: + CF-RAY: + - 9e91f4eecce8e1db-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:08 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=mNCzvUPxahtp8m2vVFSxouYduSMZiPRDGPGH422kDUJShQta8Yj%2BPqJsynh1Md%2FHXxdR9fM5yEk2PKF3GoRUq2SZ17q6SfNRGx0NXETzSwBs7YScvw6BCRBdWJrNi19xNvQu"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2110' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.019s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '995' + x-ratelimit-burst-reset: + - '0' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999938' + x-ratelimit-daily-reset: + - '34311' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '995' + x-ratelimit-reset: + - '0' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] new file mode 100644 index 0000000..87cb29c --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] @@ -0,0 +1,164 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cinvestment_title%2Cupdated_time + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cinvestment_title%2Cupdated_time","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","investment_title":"Joint Financial Management System (JFMS)","updated_time":"2026-04-06T20:01:15+00:00"},{"uii":"014-000000538","agency_name":"Department + of State","investment_title":"Security/Cybersecurity Services","updated_time":"2026-04-06T19:29:34+00:00"},{"uii":"014-000000498","agency_name":"Department + of State","investment_title":"Information Technology Acquisitions","updated_time":"2026-04-06T19:28:31+00:00"},{"uii":"014-000000534","agency_name":"Department + of State","investment_title":"GDI-IoT Network","updated_time":"2026-04-06T19:27:40+00:00"},{"uii":"014-000000520","agency_name":"Department + of State","investment_title":"FSI Enterprise Operations","updated_time":"2026-04-06T19:27:03+00:00"}]}' + headers: + CF-RAY: + - 9e91ef891c5aeac3-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:27 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=xry4jogwpj%2F2XAQ642IeGuuPvVgazCuDSHinH4vc7OLqlig6BkdwCPqtlBXnS4%2BgTMg24tmwyBqTKBpCuJ2TWTZHng1i77zKhkYCDqpXCiMW0PHoR7JRbIjSWYaUpZ3Sia0G"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '938' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.027s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '997' + x-ratelimit-burst-reset: + - '58' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999987' + x-ratelimit-daily-reset: + - '34532' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '997' + x-ratelimit-reset: + - '58' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cinvestment_title%2Cupdated_time + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cinvestment_title%2Cupdated_time","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","investment_title":"Joint Financial Management System (JFMS)","updated_time":"2026-04-06T20:01:15+00:00"},{"uii":"014-000000538","agency_name":"Department + of State","investment_title":"Security/Cybersecurity Services","updated_time":"2026-04-06T19:29:34+00:00"},{"uii":"014-000000498","agency_name":"Department + of State","investment_title":"Information Technology Acquisitions","updated_time":"2026-04-06T19:28:31+00:00"},{"uii":"014-000000534","agency_name":"Department + of State","investment_title":"GDI-IoT Network","updated_time":"2026-04-06T19:27:40+00:00"},{"uii":"014-000000520","agency_name":"Department + of State","investment_title":"FSI Enterprise Operations","updated_time":"2026-04-06T19:27:03+00:00"}]}' + headers: + CF-RAY: + - 9e91f4e8089132f4-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:07 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=WqUPwYgFV7xLDsbHhTCkYqTp0m6c0s%2FJnWeS7R1xpAqvQmgt4vWPyalKBi7QBf8kYuBW0TjDxy%2BRGy1NKaYP7Xq0SfXWd3ZjxJ2Cn4inWa7ntzlQvrfvwd2PKaSeAXdYUa3e"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '938' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.028s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '995' + x-ratelimit-burst-reset: + - '0' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999939' + x-ratelimit-daily-reset: + - '34312' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '995' + x-ratelimit-reset: + - '0' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] new file mode 100644 index 0000000..6970e5e --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] @@ -0,0 +1,184 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91ef7ffeb8ae29-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:25 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=urPVqcH31WSq70lfB9IkqSjizy%2FhKp41VcGkQrXDfLhLoEfUrDRhF62w5u6h1ACVp8JtvQWeDBm%2F9QDzMbQcc%2FevFtmOIGj6gHcGune%2FdESxCkaXrhyE%2BuE5fxy425%2FaaRvm"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2068' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.024s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '999' + x-ratelimit-burst-reset: + - '59' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999989' + x-ratelimit-daily-reset: + - '34534' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '999' + x-ratelimit-reset: + - '59' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91f4de6863eb5a-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:05 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Qt1DuHD57WKnPXfJ7Frqz8lsEoMuOkSSKUS93CxtyZm5%2Bh1JGfsTY8e9iwPRvfuqOXgNBCmuEfBM0o%2Fkffosp9cJ4b12Pi8s57b4eql2qTVvZr12Ks5aEPuDBjSRB159lC8L"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2068' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.021s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '997' + x-ratelimit-burst-reset: + - '2' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999941' + x-ratelimit-daily-reset: + - '34314' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '997' + x-ratelimit-reset: + - '2' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[minimal-uii,agency_name,bureau_name,investment_title,type_of_investment,part_of_it_portfolio,updated_time,url] b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[minimal-uii,agency_name,bureau_name,investment_title,type_of_investment,part_of_it_portfolio,updated_time,url] new file mode 100644 index 0000000..d5b4cb8 --- /dev/null +++ b/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[minimal-uii,agency_name,bureau_name,investment_title,type_of_investment,part_of_it_portfolio,updated_time,url] @@ -0,0 +1,184 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91ef83c9909a2e-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:24:26 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=F9i3HQlsAw6dyTSZgNXtEylvF4Vj5%2BicqYgOj0zCdX5rlrfEjHHUVnPONp5zvoMX7cVCO8zqgSx7Ql8qTSRUjzXdLR2jbOa5C9WJEZvTFUDBjFBuPg4xCHBo8kglxId%2BHewM"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2068' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.021s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '998' + x-ratelimit-burst-reset: + - '59' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999988' + x-ratelimit-daily-reset: + - '34533' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '998' + x-ratelimit-reset: + - '59' + x-results-counttype: + - exact + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - tango.makegov.com + user-agent: + - python-httpx/0.28.1 + method: GET + uri: https://tango.makegov.com/api/itdashboard/?page=1&limit=5&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl + response: + body: + string: '{"count":6710,"next":"https://tango.makegov.com/api/itdashboard/?limit=5&page=2&shape=uii%2Cagency_name%2Cbureau_name%2Cinvestment_title%2Ctype_of_investment%2Cpart_of_it_portfolio%2Cupdated_time%2Curl","previous":null,"results":[{"uii":"014-000000018","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Joint Financial + Management System (JFMS)","type_of_investment":"Major IT Investments","part_of_it_portfolio":"Part + 1. IT Investments for Mission Delivery","updated_time":"2026-04-06T20:01:15+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000018"},{"uii":"014-000000538","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Security/Cybersecurity + Services","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:29:34+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000538"},{"uii":"014-000000498","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"Information + Technology Acquisitions","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:28:31+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000498"},{"uii":"014-000000534","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"GDI-IoT + Network","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:40+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000534"},{"uii":"014-000000520","agency_name":"Department + of State","bureau_name":"Department of State","investment_title":"FSI Enterprise + Operations","type_of_investment":"Standard IT Investments","part_of_it_portfolio":"Part + 3. IT Standard IT Investments","updated_time":"2026-04-06T19:27:03+00:00","url":"https://www.itdashboard.gov/investment-details/014-000000520"}]}' + headers: + CF-RAY: + - 9e91f4e37edda68b-ORD + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 08 Apr 2026 14:28:06 GMT + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Y62CUuDAuac20N9hcocuWqEbuvtFfjVXvhhgrsZH8asneyzisPNOcQ0DW5x%2BqQd3eU93weo1mewrncGNpv6EuJKFMKq8mO8piDkg4LKjz%2Fpzng3AU0wBFpUxluDbv9%2BEb4QR"}]}' + Server: + - cloudflare + Transfer-Encoding: + - chunked + allow: + - GET, HEAD, OPTIONS + cf-cache-status: + - DYNAMIC + content-length: + - '2068' + cross-origin-opener-policy: + - same-origin + referrer-policy: + - same-origin + vary: + - Accept, Cookie + x-content-type-options: + - nosniff + x-execution-time: + - 0.021s + x-frame-options: + - DENY + x-ratelimit-burst-limit: + - '1000' + x-ratelimit-burst-remaining: + - '996' + x-ratelimit-burst-reset: + - '1' + x-ratelimit-daily-limit: + - '2000000' + x-ratelimit-daily-remaining: + - '1999940' + x-ratelimit-daily-reset: + - '34313' + x-ratelimit-limit: + - '1000' + x-ratelimit-remaining: + - '996' + x-ratelimit-reset: + - '1' + x-results-counttype: + - exact + status: + code: 200 + message: OK +version: 1 diff --git a/tests/integration/test_itdashboard_integration.py b/tests/integration/test_itdashboard_integration.py new file mode 100644 index 0000000..b160564 --- /dev/null +++ b/tests/integration/test_itdashboard_integration.py @@ -0,0 +1,302 @@ +"""Integration tests for IT Dashboard investment endpoints + +Pytest Markers: + @pytest.mark.integration: Marks tests as integration tests that may hit external APIs + @pytest.mark.vcr(): Enables VCR recording/playback for HTTP interactions + +Usage: + # Run only IT Dashboard integration tests + pytest tests/integration/test_itdashboard_integration.py + + # Refresh cassettes (re-record all interactions) - requires API key + TANGO_REFRESH_CASSETTES=true TANGO_API_KEY=xxx pytest tests/integration/test_itdashboard_integration.py + +API reference: https://tango.makegov.com/docs/api-reference/itdashboard.md + +Note on tier-gated filters: + The API gates several filters by access tier: + + - **Free**: ``search`` + - **Pro**: ``agency_code``, ``type_of_investment``, + ``updated_time_after`` / ``updated_time_before`` + - **Business+**: ``agency_name``, ``cio_rating``, ``cio_rating_max``, + ``performance_risk`` + + Cassettes here were recorded with a business+ key. If you re-record with a + lower-tier key, the gated filter tests will receive 403s and need updating. +""" + +from datetime import datetime + +import pytest + +from tango import ShapeConfig +from tests.integration.conftest import handle_api_exceptions +from tests.integration.validation import ( + validate_no_parsing_errors, + validate_pagination, +) + + +def _get(obj, attr): + """Read a field from a dict-like or attribute-bearing instance.""" + if isinstance(obj, dict): + return obj.get(attr) + return getattr(obj, attr, None) + + +def validate_investment_fields(investment, comprehensive: bool = False) -> None: + """Validate IT Dashboard investment has required fields and correct types.""" + uii = _get(investment, "uii") + assert uii is not None, "Investment 'uii' must not be None" + assert isinstance(uii, str), f"Investment 'uii' must be string, got {type(uii)}" + + # Optional string fields + for field in ( + "agency_name", + "bureau_name", + "investment_title", + "type_of_investment", + "part_of_it_portfolio", + "url", + ): + value = _get(investment, field) + if value is not None: + assert isinstance(value, str), ( + f"Investment '{field}' must be string, got {type(value)}" + ) + + updated_time = _get(investment, "updated_time") + if updated_time is not None: + assert isinstance(updated_time, datetime), ( + f"Investment 'updated_time' must be datetime, got {type(updated_time)}" + ) + + if comprehensive: + agency_code = _get(investment, "agency_code") + if agency_code is not None: + assert isinstance(agency_code, int), ( + f"Investment 'agency_code' must be int, got {type(agency_code)}" + ) + + +@pytest.mark.vcr() +@pytest.mark.integration +class TestITDashboardIntegration: + """Integration tests for IT Dashboard investment endpoints using production data""" + + @handle_api_exceptions("itdashboard") + @pytest.mark.parametrize( + "shape_name,shape_value", + [ + ("default", None), + ("minimal", ShapeConfig.ITDASHBOARD_INVESTMENTS_MINIMAL), + ("custom", "uii,agency_name,investment_title,updated_time"), + ], + ) + def test_list_itdashboard_investments_with_shapes( + self, tango_client, shape_name, shape_value + ): + """Test listing investments with different shapes.""" + kwargs: dict = {"limit": 5} + if shape_value is not None: + kwargs["shape"] = shape_value + + response = tango_client.list_itdashboard_investments(**kwargs) + + validate_pagination(response) + assert response.count >= 0 + + if response.results: + investment = response.results[0] + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + + @handle_api_exceptions("itdashboard") + def test_list_itdashboard_investments_with_search(self, tango_client): + """Test free-tier search filter (full-text across UII, title, description, agency, bureau).""" + response = tango_client.list_itdashboard_investments(limit=5, search="cyber") + + validate_pagination(response) + if response.results: + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + + @handle_api_exceptions("itdashboard") + def test_itdashboard_pagination(self, tango_client): + """Verify pagination returns disjoint pages.""" + page1 = tango_client.list_itdashboard_investments(limit=5, page=1) + validate_pagination(page1) + + page2 = tango_client.list_itdashboard_investments(limit=5, page=2) + validate_pagination(page2) + + if page1.results and page2.results: + uii1 = _get(page1.results[0], "uii") + uii2 = _get(page2.results[0], "uii") + assert uii1 != uii2, "Different pages should return different investments" + + @handle_api_exceptions("itdashboard") + def test_get_itdashboard_investment_by_uii(self, tango_client): + """Test get_itdashboard_investment detail using a UII from the list response.""" + response = tango_client.list_itdashboard_investments(limit=1) + validate_pagination(response) + + if not response.results: + pytest.skip("No investments returned from list to fetch by uii") + + uii = _get(response.results[0], "uii") + assert uii is not None + + detail = tango_client.get_itdashboard_investment(uii) + validate_investment_fields(detail, comprehensive=True) + validate_no_parsing_errors(detail) + + detail_uii = _get(detail, "uii") + assert detail_uii == uii, "Detail uii should match requested uii" + + # ------------------------------------------------------------------ + # Pro-tier filters + # ------------------------------------------------------------------ + + @handle_api_exceptions("itdashboard") + def test_filter_by_agency_code(self, tango_client): + """Pro-tier: filter by integer agency code (21 = Department of Transportation).""" + response = tango_client.list_itdashboard_investments(limit=5, agency_code=21) + validate_pagination(response) + + if response.results: + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + # When the shape includes agency_name, every result should be DOT. + agency_name = _get(investment, "agency_name") + if agency_name is not None: + assert "Transportation" in agency_name, ( + f"Expected DOT-affiliated agency, got {agency_name!r}" + ) + + @handle_api_exceptions("itdashboard") + def test_filter_by_type_of_investment(self, tango_client): + """Pro-tier: filter by investment type (case-insensitive iexact match).""" + response = tango_client.list_itdashboard_investments( + limit=5, type_of_investment="Major IT Investments" + ) + validate_pagination(response) + + if response.results: + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + type_of = _get(investment, "type_of_investment") + if type_of is not None: + assert type_of.lower() == "major it investments", ( + f"Expected major-it-investments, got {type_of!r}" + ) + + @handle_api_exceptions("itdashboard") + def test_filter_by_updated_time_range(self, tango_client): + """Pro-tier: filter by updated_time range using string-form ISO dates.""" + response = tango_client.list_itdashboard_investments( + limit=5, + updated_time_after="2026-01-01", + updated_time_before="2026-12-31", + ) + validate_pagination(response) + + if response.results: + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + updated = _get(investment, "updated_time") + if updated is not None: + assert updated.year == 2026, ( + f"Expected updated_time in 2026, got {updated!r}" + ) + + # ------------------------------------------------------------------ + # Business+ filters + # ------------------------------------------------------------------ + + @handle_api_exceptions("itdashboard") + def test_filter_by_agency_name_text(self, tango_client): + """Business+: text search across agency name (icontains).""" + response = tango_client.list_itdashboard_investments( + limit=5, agency_name="defense" + ) + validate_pagination(response) + + if response.results: + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + agency_name = _get(investment, "agency_name") + if agency_name is not None: + assert "defense" in agency_name.lower(), ( + f"Expected agency name containing 'defense', got {agency_name!r}" + ) + + @handle_api_exceptions("itdashboard") + def test_filter_by_cio_rating(self, tango_client): + """Business+: exact CIO risk rating (1 = High Risk).""" + response = tango_client.list_itdashboard_investments(limit=5, cio_rating=1) + validate_pagination(response) + # We only assert structural validity here — verifying the rating itself + # would require expanding cio_evaluation, which is exercised separately. + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + + @handle_api_exceptions("itdashboard") + def test_filter_by_cio_rating_max(self, tango_client): + """Business+: investments at-or-below CIO rating threshold (2 = high + moderately high).""" + response = tango_client.list_itdashboard_investments(limit=5, cio_rating_max=2) + validate_pagination(response) + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + + @handle_api_exceptions("itdashboard") + def test_filter_by_performance_risk(self, tango_client): + """Business+: investments with at least one NOT MET performance metric.""" + response = tango_client.list_itdashboard_investments( + limit=5, performance_risk=True + ) + validate_pagination(response) + for investment in response.results: + validate_investment_fields(investment) + validate_no_parsing_errors(investment) + + # ------------------------------------------------------------------ + # Shape expansions + # ------------------------------------------------------------------ + + @handle_api_exceptions("itdashboard") + def test_funding_and_cio_evaluation_expansions(self, tango_client): + """Verify ``funding`` (dict) and ``cio_evaluation`` (list-of-dict) expansions parse through.""" + response = tango_client.list_itdashboard_investments( + limit=3, + shape="uii,agency_name,funding(*),cio_evaluation(*)", + ) + validate_pagination(response) + + if not response.results: + pytest.skip("No investments returned to validate expansions") + + for investment in response.results: + assert _get(investment, "uii") is not None + funding = _get(investment, "funding") + if funding is not None: + assert isinstance(funding, dict), ( + f"funding must be dict, got {type(funding)}" + ) + cio_eval = _get(investment, "cio_evaluation") + if cio_eval is not None: + assert isinstance(cio_eval, list), ( + f"cio_evaluation must be list, got {type(cio_eval)}" + ) + for entry in cio_eval: + assert isinstance(entry, dict), ( + f"cio_evaluation entries must be dicts, got {type(entry)}" + ) diff --git a/tests/test_client.py b/tests/test_client.py index 3ffb15d..2bc9004 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -335,6 +335,149 @@ def test_list_subawards_with_default_shape(self, mock_request): # Default shape does not include id (API rejects it); assert on award_key assert subawards.results[0]["award_key"] == "CONT_AWD_123" + @patch("tango.client.httpx.Client.request") + def test_list_itdashboard_investments_with_default_shape(self, mock_request): + """Test list_itdashboard_investments uses default minimal shape and hits the right URL.""" + mock_response = Mock() + mock_response.is_success = True + mock_response.json.return_value = { + "count": 1, + "next": None, + "previous": None, + "results": [ + { + "uii": "021-000000001", + "agency_name": "Department of Transportation", + "bureau_name": "Federal Aviation Administration", + "investment_title": "NextGen Air Traffic", + "type_of_investment": "Major IT Investment", + "part_of_it_portfolio": "Yes", + "updated_time": "2024-01-15T12:00:00Z", + "url": "https://www.itdashboard.gov/investment-details/021-000000001", + } + ], + } + mock_response.content = b'{"count": 1}' + mock_request.return_value = mock_response + + client = TangoClient(api_key="test-key") + investments = client.list_itdashboard_investments(limit=10) + + call_args = mock_request.call_args + # Hits /api/itdashboard/, not /api/itdashboard_investments/ + assert call_args[1]["url"].endswith("/api/itdashboard/") + assert call_args[1]["params"]["shape"] == ShapeConfig.ITDASHBOARD_INVESTMENTS_MINIMAL + assert investments.count == 1 + assert investments.results[0]["uii"] == "021-000000001" + assert isinstance(investments.results[0]["updated_time"], datetime) + + @patch("tango.client.httpx.Client.request") + def test_list_itdashboard_investments_passes_filters(self, mock_request): + """Test that all filter params are forwarded with correct serialization.""" + mock_response = Mock() + mock_response.is_success = True + mock_response.json.return_value = { + "count": 0, + "next": None, + "previous": None, + "results": [], + } + mock_response.content = b'{"count": 0}' + mock_request.return_value = mock_response + + client = TangoClient(api_key="test-key") + client.list_itdashboard_investments( + search="cyber", + agency_code=21, + agency_name="defense", + type_of_investment="Major IT Investment", + updated_time_after=date(2024, 1, 1), + updated_time_before="2024-12-31", + cio_rating=1, + cio_rating_max=2, + performance_risk=True, + ) + + params = mock_request.call_args[1]["params"] + assert params["search"] == "cyber" + assert params["agency_code"] == 21 + assert params["agency_name"] == "defense" + assert params["type_of_investment"] == "Major IT Investment" + assert params["updated_time_after"] == "2024-01-01" + assert params["updated_time_before"] == "2024-12-31" + assert params["cio_rating"] == 1 + assert params["cio_rating_max"] == 2 + # Booleans are serialized as the lowercase strings the API expects. + assert params["performance_risk"] == "true" + + @patch("tango.client.httpx.Client.request") + def test_get_itdashboard_investment_by_uii(self, mock_request): + """Test get_itdashboard_investment uses UII in path and comprehensive default shape.""" + mock_response = Mock() + mock_response.is_success = True + mock_response.json.return_value = { + "uii": "021-000000001", + "agency_code": 21, + "agency_name": "DOT", + "bureau_code": 12, + "bureau_name": "FAA", + "investment_title": "NextGen", + "type_of_investment": "Major IT Investment", + "part_of_it_portfolio": "Yes", + "updated_time": "2024-01-15T12:00:00Z", + "url": "https://www.itdashboard.gov/investment-details/021-000000001", + } + mock_response.content = b'{"uii": "021-000000001"}' + mock_request.return_value = mock_response + + client = TangoClient(api_key="test-key") + investment = client.get_itdashboard_investment("021-000000001") + + call_args = mock_request.call_args + assert call_args[1]["url"].endswith("/api/itdashboard/021-000000001/") + assert ( + call_args[1]["params"]["shape"] + == ShapeConfig.ITDASHBOARD_INVESTMENTS_COMPREHENSIVE + ) + assert investment["uii"] == "021-000000001" + assert investment["agency_code"] == 21 + + @patch("tango.client.httpx.Client.request") + def test_list_itdashboard_investments_funding_expansion(self, mock_request): + """Test that funding/details dict expansions and nested-list expansions parse through.""" + mock_response = Mock() + mock_response.is_success = True + mock_response.json.return_value = { + "count": 1, + "next": None, + "previous": None, + "results": [ + { + "uii": "021-X", + "agency_name": "DOT", + "funding": { + "fy2024_internal_funding": "1000000.00", + "fy2024_contribution": "50000.00", + }, + "cio_evaluation": [ + {"cioRating": "3 - Medium Risk", "latestIndicator": "Y"} + ], + } + ], + } + mock_response.content = b'{"count": 1}' + mock_request.return_value = mock_response + + client = TangoClient(api_key="test-key") + investments = client.list_itdashboard_investments( + shape="uii,agency_name,funding(*),cio_evaluation(*)" + ) + + result = investments.results[0] + assert result["uii"] == "021-X" + assert result["funding"]["fy2024_internal_funding"] == "1000000.00" + assert result["cio_evaluation"][0]["latestIndicator"] == "Y" + @patch("tango.client.httpx.Client.request") def test_error_handling_401(self, mock_request): """Test 401 authentication error handling""" diff --git a/uv.lock b/uv.lock index b84996e..0edfd6b 100644 --- a/uv.lock +++ b/uv.lock @@ -1831,7 +1831,7 @@ wheels = [ [[package]] name = "tango-python" -version = "0.4.2" +version = "0.5.0" source = { editable = "." } dependencies = [ { name = "httpx" },